mysql - Mongoosejs : Cleanest way to select rows with `limit` and `where` , 然后获取总数

标签 mysql node.js mongodb mongoose

当我使用 PHPMySQL 时,我需要选择行数,然后计算总数(对于分页,例如maple),我会执行以下操作:

$rows = DB::getRows('
    SQL_CALC_FOUND_ROWS
    select * 
    from posts 
    where mode = "published" 
    order by `dateCreated` 
    limit '.$limit.'
');

然后

$totalRows = DB::getOne('
    SELECT FOUND_ROWS()
');

简单易行。

最近我开始从事 nodejs/mongo 项目,我想知道使用 mongoose 实现相同目标的最干净的方法是什么。

现在我的代码如下所示:

var result = {};

var sort = {dateCreated: -1};
var skip = limit * (page - 1);

modelClass.find(function (err, items) {

    result.items = items;

    modelClass.find().where('mode').equals('published').count(function (err, total) {
        result.totalItems = total;
        callback([], result);
    });

}).where('mode').equals('published').sort(sort).limit(limit).skip(skip);

我不喜欢的是我在 .where('mode').equals('published') 中重复自己。

有更好的方法吗?

最佳答案

似乎您想要对数据进行分页。
检查这个例子:

var async = require('async');
var _ = require('lodash');

function getData(query, page, callback) { // wrap it inside function to reuse it
    if(page < 1) page = 1; // make sure page number = 1 if it's out of minimal bounds

    var query = _.extend({mode: 'published'}, query); // make it to be able to add additional parameters
    var sort = {dateCreated: -1}; 
    var limit = 50;
    var skip = limit * (page - 1);

    // making 2 parallel calls, not harming readability
    async.parallel([ // array of calls

      // 0. get count by query and send it to parallel result handler
      modelClass
        .find(query)
        .count()
        .exec,

      // 1. get records by defined query and send it parallel handler
      modelClass
        .find(query)
        .sort(sort)
        .limit(limit)
        .skip(skip)
        .exec
    ],

    // parallel result handler - callback, results of each function sent by index in array above
    function(err, results) {
      if(err) {
        return callback(err);
      }     

      // aggregating result in easy to use object 
      var result = {
          count: results[0], // where we get count
          page: page,
          pages: Math.ceil(results[0] / limit), 
          perPage: limit,
          records: results[1] // where we get documents
      };
      callback(null, result);
    });
}

用法:

getData({}, 2, function(err, result) {
  console.log('Pages:', result.pages, 'Total records:', result.count);
  console.log('Per page:', result.perPage, 'Current page:', result.page);
  console.log('Records:', result.records);
});

getData({publishedBy: 'user-id-here'}, 5, function(err, result) {
  // same example code
});

附:由于多行代码,这段代码看起来非常庞大。
因此最好有一些全局函数,例如:countRecordsByModel、getRecordsByModel、paginateRecordsByModel,您可以将模型、查询、页面、回调作为参数。
它将缩短您的代码以供将来重用。

使上面的所有代码更加灵活,因此只需通过传递 mongoose 模型作为参数、查询、页码和回调函数来调用 paginateRecordsByModel 即可。

采取这段代码:

var async = require('async');
var _ = require('lodash');

function countRecordsByModel(modelClass, query, callback) {
  modelClass
    .find(query)
    .count()
    .exec(callback);
}

function getRecordsByModel(modelClass, query, page, callback) {
  if(page < 1) page = 1; 
  var query = _.extend({}, query);

  /* or can extend it with default params like:

  var query = _.extend({deleted: false}, query); // in my databases I have deleted field, to flag documents as deleted, I delete them physically after a month, by garbage cleaner.
  */

  var sort = {dateCreated: -1}; 
  var limit = 50;
  var skip = limit * (page - 1);

  modelClass
    .find(query)
    .sort(sort)
    .limit(limit)
    .skip(skip)
    .exec(callback);
}

function paginateRecordsByModel(modelClass, query, page, callback) {

    // making 2 parallel calls, not harming readability
    async.parallel([ // array of calls

      // 0. get count by query and send it to parallel result handler
      function(done) {
        countRecordsByModel(modelClass, query, done)
      },

      // 1. get records by defined query and send it parallel handler
      function(done) {
        getRecordsByModel(modelClass, query, page, done);
      }

    ],

    // parallel result handler - callback, results of each function sent by index in array above
    function(err, results) {
      if(err) {
        return callback(err);
      }     

      // aggregating result in easy to use object 
      var result = {
          count: results[0], // where we get count
          page: page,
          pages: Math.ceil(results[0] / limit), 
          perPage: limit,
          records: results[1] // where we get documents
      };
      callback(null, result);
    });
}

用法:

paginateRecordsByModel(postsModel, {mode: 'published'}, function(err, result) {
  console.log('Pages:', result.pages, 'Total records:', result.count);
  console.log('Per page:', result.perPage, 'Current page:', result.page);
  console.log('Records:', result.records);
});

关于mysql - Mongoosejs : Cleanest way to select rows with `limit` and `where` , 然后获取总数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34280996/

相关文章:

mongodb - 在 mongoimport --jsonArray 上的子文档上创建 _id

java - 如何将Recyclerview从最后一个ID到第一个ID排序?

mysql - 根据第二列使用同一列的最小值更新列

node.js socket.io room 用户总数

javascript - 在 Node/Electron 环境中共享 ESM ".js"模块

javascript - Mongoose - RangeError : Maximum Call Stack Size Exceeded

php - 使用 php 格式化日期并添加或减去来自 mysql 的日期中的天数

php - 非重复数据

node.js - DynamoDB 记录未通过 map 循环添加

node.js - MongoDB:使用 $geoNear 并非所有结果都从查询返回