MongoDB - 分页

Rog*_*son 75 paging mongodb

使用MongoDB时,是否有任何特殊模式可用于制作分页视图?说一个博客列出了10个最新帖子,你可以向后导航到较旧的帖子.

或者用例如blogpost.publishdate上的索引来解决它,然后跳过并限制结果?

Sco*_*dez 93

使用skip + limit不是在性能问题或大型集合时进行分页的好方法; 当你增加页码时,它会越来越慢.使用skip需要服务器遍历从0到偏移(跳过)值的所有文档(或索引值).

最好使用范围查询(+ limit)传递最后一页的范围值.例如,如果按"publishdate"排序,则可以简单地将最后一个"publishdate"值作为查询的条件传递,以获取下一页数据.

  • 这是[skip docs link](http://docs.mongodb.org/manual/reference/method/cursor.skip/#cursor.skip) (7认同)
  • 如果有多个文档具有相同的publishdate值,则似乎这样做不起作用. (6认同)
  • 在这里你去:[跳过文档](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bskip%28%29%7D%7D)如果还有其他任何地方信息应该更新请告诉我. (5认同)
  • 很高兴看到一些文件证实在mongodb中跳过遍历所有文档. (4认同)
  • @ScottHernandez:我有分页链接到多个页面(如:Page:First,2,3,4,5,Last)并对所有字段进行排序.我的字段中只有一个是唯一的(并且已编入索引),范围查询是否适用于此用例?我不敢,我只是想确认一下是否可能.谢谢. (2认同)

jac*_*ope 11

  1. 如果需要以多种方式对项目进行排序,则难以实现基于范围的分页.
  2. 请记住,如果sort参数的字段值不唯一,则基于范围的分页将变得不可实现.

可能的解决方案:尝试简化设计,考虑我们是否只能按id或某些唯一值排序?

如果可以的话,可以使用基于范围的分页.

常见的方法是使用sort(),skip()和limit()来实现上面描述的分页.


mz3*_*mz3 5

这是我在我的集​​合变得太大而无法在单个查询中返回时使用的解决方案.它利用了_id字段的固有顺序,允许您按指定的批处理大小循环访问集合.

这里是一个npm模块,mongoose-paging,完整代码如下:

function promiseWhile(condition, action) {
  return new Promise(function(resolve, reject) {
    process.nextTick(function loop() {
      if(!condition()) {
        resolve();
      } else {
        action().then(loop).catch(reject);
      }
    });
  });
}

function findPaged(query, fields, options, iterator, cb) {
  var Model  = this,
    step     = options.step,
    cursor   = null,
    length   = null;

  promiseWhile(function() {
    return ( length===null || length > 0 );
  }, function() {
    return new Promise(function(resolve, reject) {

        if(cursor) query['_id'] = { $gt: cursor };

        Model.find(query, fields, options).sort({_id: 1}).limit(step).exec(function(err, items) {
          if(err) {
            reject(err);
          } else {
            length  = items.length;
            if(length > 0) {
              cursor  = items[length - 1]._id;
              iterator(items, function(err) {
                if(err) {
                  reject(err);
                } else {
                  resolve();
                }
              });
            } else {
              resolve();
            }
          }
        });
      });
  }).then(cb).catch(cb);

}

module.exports = function(schema) {
  schema.statics.findPaged = findPaged;
};
Run Code Online (Sandbox Code Playgroud)

将它附加到您的模型,如下所示:

MySchema.plugin(findPaged);
Run Code Online (Sandbox Code Playgroud)

然后像这样查询:

MyModel.findPaged(
  // mongoose query object, leave blank for all
  {source: 'email'},
  // fields to return, leave blank for all
  ['subject', 'message'],
  // number of results per page
  {step: 100},
  // iterator to call on each set of results
  function(results, cb) {
    console.log(results);
    // this is called repeatedly while until there are no more results.
    // results is an array of maximum length 100 containing the
    // results of your query

    // if all goes well
    cb();

    // if your async stuff has an error
    cb(err);
  },
  // function to call when finished looping
  function(err) {
    throw err;
    // this is called once there are no more results (err is null),
    // or if there is an error (then err is set)
  }
);
Run Code Online (Sandbox Code Playgroud)

  • 这个答案如何工作,在任何其他领域进行排序? (5认同)