Results pagination in Cassandra (CQL)

后端 未结 6 1773
一生所求
一生所求 2020-12-08 04:33

I am wondering how can I achieve pagination using Cassandra.

Let us say that I have a blog. The blog lists max 10 posts per page. To access next posts a user must cl

6条回答
  •  一向
    一向 (楼主)
    2020-12-08 04:57

    Using cassandra-node driver for node js (koa js,marko js) : Pagination Problem

    Due to the absence of skip functionality, we need to work around. Below is the implementation of manual paging for node app in case of anyone can get an idea.

    • code for simple users list
    • navigate between next and previous page states
    • easy to replicate

    There are two solutions which i am going to state here but only gave the code for solution 1 below,

    Solution 1 : Maintain page states for next and previous records (maintain stack or whatever data structure best fit)

    Solution 2 : Loop through all records with limit and save all possible page states in variable and generate pages relatively to their pageStates

    Using this commented code in model, we can get all states for pages

                //for the next flow
                //if (result.nextPage) {
                // Retrieve the following pages:
                // the same row handler from above will be used
                // result.nextPage();
                //}
    

    Router Functions

        var userModel = require('/models/users');
              public.get('/users', users);
              public.post('/users', filterUsers);
    
        var users = function* () {//get request
            var data = {};
            var pageState = { "next": "", "previous": "" };
            try {
                var userCount = yield userModel.Count();//count all users with basic count query
    
                var currentPage = 1;
                var pager = yield generatePaging(currentPage, userCount, pagingMaxLimit);
                var userList = yield userModel.List(pager);
                data.pageNumber = currentPage;
                data.TotalPages = pager.TotalPages;
                console.log('--------------what now--------------');
                data.pageState_next = userList.pageStates.next;
                data.pageState_previous = userList.pageStates.previous;
                console.log("next ", data.pageState_next);
                console.log("previous ", data.pageState_previous);
    
                data.previousStates = null;
    
                data.isPrevious = false;
                if ((userCount / pagingMaxLimit) > 1) {
                    data.isNext = true;
                }
    
                data.userList = userList;
                data.totalRecords = userCount;
                console.log('--------------------userList--------------------', data.userList);
                //pass to html template
            }
            catch (e) {
                console.log("err ", e);
                log.info("userList error : ", e);
            }
       this.body = this.stream('./views/userList.marko', data);
       this.type = 'text/html';
        };
    
        //post filter and get list
        var filterUsers = function* () {
            console.log("<------------------Form Post Started----------------->");
            var data = {};
            var totalCount;
            data.isPrevious = true;
            data.isNext = true;
    
            var form = this.request.body;
            console.log("----------------formdata--------------------", form);
            var currentPage = parseInt(form.hdpagenumber);//page number hidden in html
            console.log("-------before current page------", currentPage);
            var pageState = null;
            try {
                var statesArray = [];
                if (form.hdallpageStates && form.hdallpageStates !== '') {
                    statesArray = form.hdallpageStates.split(',');
                }
                console.log(statesArray);
    
                //develop stack to track paging states
                if (form.hdpagestateRequest === 'next') {
                    console.log('--------------------------next---------------------');
                    currentPage = currentPage + 1;
                    statesArray.push(form.hdpageState_next);
                    pageState = form.hdpageState_next;
                }
                else if (form.hdpagestateRequest === 'previous') {
                    console.log('--------------------------pre---------------------');
                    currentPage = currentPage - 1;
                    var p_st = statesArray.length - 2;//second last index
                    console.log('this index of array to be removed ', p_st);
                    pageState = statesArray[p_st];
                    statesArray.splice(p_st, 1);
                    //pageState = statesArray.pop();
                }
                else if (form.hdispaging === 'false') {
                    currentPage = 1;
                    pageState = null;
                    statesArray = [];
                }
    
    
                data.previousStates = statesArray;
                console.log("paging true");
    
                totalCount = yield userModel.Count();
    
                var pager = yield generatePaging(form.hdpagenumber, totalCount, pagingMaxLimit);
                data.pageNumber = currentPage;
                data.TotalPages = pager.TotalPages;
    
                //filter function - not yet constructed
                var searchUsers = yield userModel.searchList(pager, pageState);
                data.usersList = searchUsers;
                if (searchUsers.pageStates) {
                    data.pageStates = searchUsers.pageStates;
                    data.next = searchUsers.nextPage;
                    data.pageState_next = searchUsers.pageStates.next;
                    data.pageState_previous = searchUsers.pageStates.previous;
    
                    //show previous and next buttons accordingly
                    if (currentPage == 1 && pager.TotalPages > 1) {
                        data.isPrevious = false;
                        data.isNext = true;
                    }
                    else if (currentPage == 1 && pager.TotalPages <= 1) {
                        data.isPrevious = false;
                        data.isNext = false;
                    }
                    else if (currentPage >= pager.TotalPages) {
                        data.isPrevious = true;
                        data.isNext = false;
                    }
                    else {
                        data.isPrevious = true;
                        data.isNext = true;
                    }
                }
                else {
                    data.isPrevious = false;
                    data.isNext = false;
                }
                console.log("response ", searchUsers);
                data.totalRecords = totalCount;
    
               //pass to html template
            }
            catch (e) {
                console.log("err ", e);
                log.info("user list error : ", e);
            }
            console.log("<------------------Form Post Ended----------------->");
       this.body = this.stream('./views/userList.marko', data);
       this.type = 'text/html';
        };
    
        //Paging function
        var generatePaging = function* (currentpage, count, pageSizeTemp) {
            var paging = new Object();
            var pagesize = pageSizeTemp;
            var totalPages = 0;
            var pageNo = currentpage == null ? null : currentpage;
            var skip = pageNo == null ? 0 : parseInt(pageNo - 1) * pagesize;
            var pageNumber = pageNo != null ? pageNo : 1;
            totalPages = pagesize == null ? 0 : Math.ceil(count / pagesize);
            paging.skip = skip;
            paging.limit = pagesize;
            paging.pageNumber = pageNumber;
            paging.TotalPages = totalPages;
            return paging;
        };
    

    Model Functions

        var clientdb = require('../utils/cassandradb')();
        var Users = function (options) {
          //this.init();
          _.assign(this, options);
        };
    
        Users.List = function* (limit) {//first time
                var myresult; var res = [];
                res.pageStates = { "next": "", "previous": "" };
    
                const options = { prepare: true, fetchSize: limit };
                console.log('----------did i appeared first?-----------');
    
                yield new Promise(function (resolve, reject) {
                    clientdb.eachRow('SELECT * FROM users_lookup_history', [], options, function (n, row) {
                        console.log('----paging----rows');
                        res.push(row);
                    }, function (err, result) {
                        if (err) {
                            console.log("error ", err);
                        }
                        else {
                            res.pageStates.next = result.pageState;
                            res.nextPage = result.nextPage;//next page function
                        }
                        resolve(result);
                    });
                }).catch(function (e) {
                    console.log("error ", e);
                }); //promise ends
    
                console.log('page state ', res.pageStates);
                return res;
            };
    
            Users.searchList = function* (pager, pageState) {//paging filtering
                console.log("|------------Query Started-------------|");
                console.log("pageState if any ", pageState);
                var res = [], myresult;
                res.pageStates = { "next": "" };
                var query = "SELECT * FROM users_lookup_history ";
                var params = [];
    
                console.log('current pageState ', pageState);
                const options = { pageState: pageState, prepare: true, fetchSize: pager.limit };
                console.log('----------------did i appeared first?------------------');
    
                yield new Promise(function (resolve, reject) {
                    clientdb.eachRow(query, [], options, function (n, row) {
                        console.log('----Users paging----rows');
                        res.push(row);
                    }, function (err, result) {
                        if (err) {
                            console.log("error ", err);
                        }
                        else {
                            res.pageStates.next = result.pageState;
                            res.nextPage = result.nextPage;
                        }
                        //for the next flow
                        //if (result.nextPage) {
                        // Retrieve the following pages:
                        // the same row handler from above will be used
                        // result.nextPage();
                        //}
                        resolve(result);
                    });
                }).catch(function (e) {
                    console.log("error ", e);
                    info.log('something');
                }); //promise ends
    
                console.log('page state ', pageState);
    
                console.log("|------------Query Ended-------------|");
                return res;
            };
    

    Html side

            
    

    I am not very much experienced with node js and cassandra db, this solution can surely be improved. Solution 1 is working example code to start with the paging idea. Cheers

提交回复
热议问题