Node.js API分页、筛选、排序与客户端分页、筛选、排序

Node.js API分页、筛选、排序与客户端分页、筛选、排序,node.js,database,rest,api,pagination,Node.js,Database,Rest,Api,Pagination,场景 网站页面具有具有分页、筛选和排序的表视图 表中的数据是从RESTAPI服务器获取的,数据包含 数百万张唱片 数据库REST API服务器Web服务器浏览器 问题 哪里是进行分页、筛选和排序的最佳位置 可能的解决方案 在web服务器中分页、筛选、排序 REST API服务器发送完整列表(请求的实体可能不需要) web服务器必须使用逻辑进行分页、筛选、排序,这可能会增加负载 若web服务器只想记录RESTAPI,那个么服务器需要有单独的API,否则web服务器必须从完整列表中解

场景

  • 网站页面具有具有分页、筛选和排序的表视图

  • 表中的数据是从RESTAPI服务器获取的,数据包含 数百万张唱片

  • 数据库REST API服务器Web服务器浏览器


问题

  • 哪里是进行分页、筛选和排序的最佳位置

可能的解决方案

  • 在web服务器中分页、筛选、排序

    • REST API服务器发送完整列表(请求的实体可能不需要)
    • web服务器必须使用逻辑进行分页、筛选、排序,这可能会增加负载
    • 若web服务器只想记录RESTAPI,那个么服务器需要有单独的API,否则web服务器必须从完整列表中解析
  • 在REST API服务器中分页、筛选、排序

    • RESTAPI服务器接受输入参数并进行分页、筛选和排序
    • web服务器可以直接将其绑定到表视图,而无需格式化结果
    • 只发送请求的数据,因此节省了带宽
    • 更像谷歌的融合表api


在不违反REST API标准的情况下,最好的方法是什么?

/*处理分页*/ 路由器.post('/products/view front',功能(req,res){

/*设置我们的内部DB变量*/
var db=请求db;
/*设置我们的收藏*/
products=db.get(“products”);
pag_含量=“”;
pag_导航=“”;
page=parseInt(req.body.data.page);/*我们当前所在的页面*/
name=req.body.data.name;/*要排序的列名的名称*/
sort=req.body.data.sort==“ASC”?1:-1;/*我们的排序顺序(DESC或ASC)*/
max=parseInt(req.body.data.max);/*每页显示的项目数*/
search=req.body.data.search;/*关键字在搜索框中提供*/
cur_page=第页;
第-=1页;
每页=最大值?最大值:20;
上一个_btn=真;
next_btn=真;
第一_btn=真;
last_btn=真;
开始=每页*页;
其中_search={};
/*检查搜索框上是否输入了字符串*/
如果(搜索!=''){
/*如果输入了字符串,则在主查询中包含一个额外的查询逻辑以过滤结果*/
var filter=newregexp(搜索“i”);
其中,搜索={
“$or”:[
{'name':过滤器},
{'price':过滤器},
]
}
}
var all_项目=“”;
var计数=“”;
var sort_query={};
/*我们使用async任务来确保我们只在所有查询成功完成时返回数据*/
异步并行([
函数(回调){
/*使用名称和排序变量作为字段名*/
排序\查询[名称]=排序;
/*检索所有帖子*/
products.find(where_search{
限制:每页,
跳过:开始,
排序:排序查询
},函数(错误,文档){
如果(错误)抛出错误;
//console.log(文档);
所有项目=单据;
回调();
});
},
函数(回调){
products.count(其中搜索、函数(错误、文档计数){
如果(错误)抛出错误;
//控制台日志(计数);
计数=单据计数;
回调();
});
}
],函数(err){//这是最后的回调
/*检查我们的查询是否返回任何内容*/
如果(计数){
for(所有_项中的var键){
pag_内容+=“”+
'' +
'' +
所有\u项[键]。名称+
'' +
'' +
'' +
'' +
'' +
'' +
“

Price

”+ “$”+parseFloat(所有项目[key].price.toFixed(2)+”+ '' + '' + '' + “

数量+ ''+所有项目[键]。数量+''+ '' + '' + '' + '' + “

”+ '' + '' + ''; } } pag_content=pag_content+“
”; 无分页=Math.ceil(计数/每页); 如果(当前页面>=7){ 开始循环=当前第3页; 如果(无分页>当前页面+3) 结束循环=当前页面+3; else if(当前页码,共6页){ start_loop=no_of_pagination-6; end_loop=没有分页; }否则{ end_loop=没有分页; } }否则{ 开始循环=1; 如果(没有分页>7的分页) 结束循环=7; 其他的 end_loop=没有分页; } pag_导航+=“
    ”; 如果(第一页和当前页>1){ pag_导航+=“
  • 第一个”
  • ”; }否则,如果(第一个){ pag_导航+=“
  • 第一个”
  • ”; } 如果(上一页和当前页>1){ pre=当前页面-1; pag_导航+=“
  • 上一个
  • ”; }否则如果(上一个){ pag_导航+=“
  • 上一个”
  • ”; }
    for(i=start_loop;i/*处理分页*/ 路由器.post('/products/view front',功能(req,res){

    /*设置我们的内部DB变量*/
    var db=请求db;
    /*设置我们的收藏*/
    products=db.get(“products”);
    pag_含量=“”;
    pag_导航=“”;
    page=parseInt(req.body.data.page);/*当前页面
    
    /* Set our internal DB variable */
    var db = req.db;
    
        /* Set our collection */
        products = db.get('products');
    
        pag_content = '';
        pag_navigation = '';
    
        page = parseInt(req.body.data.page); /* Page we are currently at */
        name = req.body.data.name; /* Name of the column name we want to sort */
        sort = req.body.data.sort == 'ASC' ? 1 : -1; /* Order of our sort (DESC or ASC) */
        max = parseInt(req.body.data.max); /* Number of items to display per page */
        search = req.body.data.search; /* Keyword provided on our search box */
    
        cur_page = page;
        page -= 1;
        per_page = max ? max : 20;
        previous_btn = true;
        next_btn = true;
        first_btn = true;
        last_btn = true;
        start = page * per_page;
    
        where_search = {};
    
    /* Check if there is a string inputted on the search box */
    if( search != '' ){
        /* If a string is inputted, include an additional query logic to our main query to filter the results */
        var filter = new RegExp(search, 'i');
        where_search = {
            '$or' : [
                {'name' : filter},
                {'price' : filter},
            ]
        }
    }
    
    var all_items = '';
    var count = '';
    var sort_query = {};
    
    /* We use async task to make sure we only return data when all queries completed successfully */
    async.parallel([
        function(callback) {
            /* Use name and sort variables as field names */
            sort_query[name] = sort;
    
            /* Retrieve all the posts */
            products.find( where_search, {
                limit: per_page,
                skip: start,
                sort: sort_query
    
            }, function(err, docs){
                if (err) throw err;
                // console.log(docs);
                all_items = docs;
                callback();
    
            });
        },
        function(callback) {
            products.count(where_search, function(err, doc_count){
                if (err) throw err;
                // console.log(count);
                count = doc_count;
                callback();
            });
        }
    ], function(err) { //This is the final callback
        /* Check if our query returns anything. */
        if( count ){
            for (var key in all_items) {
                pag_content += '<div class="col-sm-3">' +
                    '<div class="panel panel-default">' +
                        '<div class="panel-heading">' +
                            all_items[key].name +
                        '</div>' +
                        '<div class="panel-body p-0 p-b">' +
                            '<a href="products-single.php?item=' + all_items[key]._id + '"><img src="img/uploads/' + all_items[key].featured_image + '" width="100%" class="img-responsive" /></a>' +
                            '<div class="list-group m-0">' +
                                '<div class="list-group-item b-0 b-t">' +
                                    '<i class="fa fa-calendar-o fa-2x pull-left ml-r"></i>' +
                                    '<p class="list-group-item-text">Price</p>' +
                                    '<h4 class="list-group-item-heading">$' + parseFloat(all_items[key].price).toFixed(2) + '</h4>' +
                                '</div>' +
                                '<div class="list-group-item b-0 b-t">' +
                                    '<i class="fa fa-calendar fa-2x pull-left ml-r"></i>' +
                                    '<p class="list-group-item-text">Quantity</p>' +
                                    '<h4 class="list-group-item-heading">' + all_items[key].quantity + '</h4>' +
                                '</div>' +
                            '</div>' +
                        '</div>' +
                        '<div class="panel-footer">' +
                            '</p><a href="products-single.php?item=' + all_items[key]._id + '" class="btn btn-success btn-block">View Item</a></p>' +
                         '</div>' +
                    '</div>' +
                '</div>';
            }
        }
    
        pag_content = pag_content + "<br class = 'clear' />";
    
        no_of_paginations = Math.ceil(count / per_page);
    
        if (cur_page >= 7) {
            start_loop = cur_page - 3;
            if (no_of_paginations > cur_page + 3)
                end_loop = cur_page + 3;
            else if (cur_page <= no_of_paginations && cur_page > no_of_paginations - 6) {
                start_loop = no_of_paginations - 6;
                end_loop = no_of_paginations;
            } else {
                end_loop = no_of_paginations;
            }
        } else {
            start_loop = 1;
            if (no_of_paginations > 7)
                end_loop = 7;
            else
                end_loop = no_of_paginations;
        }
    
        pag_navigation += "<ul>";
    
        if (first_btn && cur_page > 1) {
            pag_navigation += "<li p='1' class='active'>First</li>";
        } else if (first_btn) {
            pag_navigation += "<li p='1' class='inactive'>First</li>";
        }
    
        if (previous_btn && cur_page > 1) {
            pre = cur_page - 1;
            pag_navigation += "<li p='" + pre + "' class='active'>Previous</li>";
        } else if (previous_btn) {
            pag_navigation += "<li class='inactive'>Previous</li>";
        }
        for (i = start_loop; i <= end_loop; i++) {
    
            if (cur_page == i)
                pag_navigation += "<li p='" + i + "' class = 'selected' >" + i + "</li>";
            else
                pag_navigation += "<li p='" + i + "' class='active'>" + i + "</li>";
        }
    
        if (next_btn && cur_page < no_of_paginations) {
            nex = cur_page + 1;
            pag_navigation += "<li p='" + nex + "' class='active'>Next</li>";
        } else if (next_btn) {
            pag_navigation += "<li class='inactive'>Next</li>";
        }
    
        if (last_btn && cur_page < no_of_paginations) {
            pag_navigation += "<li p='" + no_of_paginations + "' class='active'>Last</li>";
        } else if (last_btn) {
            pag_navigation += "<li p='" + no_of_paginations + "' class='inactive'>Last</li>";
        }
    
        pag_navigation = pag_navigation + "</ul>";
    
        var response = {
            'content': pag_content,
            'navigation' : pag_navigation
        };
    
        res.send(response);
    
    });