【问题标题】:Mongoosejs: Cleanest way to select rows with `limit` and `where`, then get count of totalMongoosejs:使用“limit”和“where”选择行的最简洁方法,然后获取总数
【发布时间】:2016-03-20 18:11:27
【问题描述】:

当我使用 PHPMySQL 时,我需要选择行数然后计算总数(例如分页),我会这样做:

$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') 中重复自己。

有没有更好的方法?

【问题讨论】:

标签: mysql node.js mongodb mongoose


【解决方案1】:

好像你想要分页数据。
检查这个例子:

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 where You push,model, query, page, callback 作为参数。
它将缩短您的代码以供将来重用。

使上述所有代码更加灵活,因此只需通过传递 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);
});

【讨论】:

    猜你喜欢
    • 2014-11-12
    • 1970-01-01
    • 2021-01-29
    • 1970-01-01
    • 2023-01-12
    • 2011-01-09
    • 1970-01-01
    • 2013-02-06
    • 1970-01-01
    相关资源
    最近更新 更多