我正在用Node.js和mongoose写一个web应用程序。如何对我从.find()调用得到的结果进行分页?我想要一个功能可比的“限制50,100”在SQL。


当前回答

在用Rodolphe提供的信息仔细研究了Mongoose API后,我想出了这个解决方案:

MyModel.find(query, fields, { skip: 10, limit: 5 }, function(err, results) { ... });

其他回答

有一些很好的答案给出了使用skip()和limit()的解决方案,但是,在某些情况下,我们还需要文档计数来生成分页。以下是我们在项目中所做的:

const PaginatePlugin = (schema, options) => {
  options = options || {}
  schema.query.paginate = async function(params) {
    const pagination = {
      limit: options.limit || 10,
      page: 1,
      count: 0
    }
    pagination.limit = parseInt(params.limit) || pagination.limit
    const page = parseInt(params.page)
    pagination.page = page > 0 ? page : pagination.page
    const offset = (pagination.page - 1) * pagination.limit

    const [data, count] = await Promise.all([
      this.limit(pagination.limit).skip(offset),
      this.model.countDocuments(this.getQuery())
    ]);
    pagination.count = count;
    return { data, pagination }
  }
}

mySchema.plugin(PaginatePlugin, { limit: DEFAULT_LIMIT })

// using async/await
const { data, pagination } = await MyModel.find(...)
  .populate(...)
  .sort(...)
  .paginate({ page: 1, limit: 10 })

// or using Promise
MyModel.find(...).paginate(req.query)
  .then(({ data, pagination }) => {

  })
  .catch(err => {

  })

尝试使用mongoose函数进行分页。限制是每页的记录数量和页的数量。

var limit = parseInt(body.limit);
var skip = (parseInt(body.page)-1) * parseInt(limit);

 db.Rankings.find({})
            .sort('-id')
            .limit(limit)
            .skip(skip)
            .exec(function(err,wins){
 });

最好的方法(IMO)是在有限的集合或文档中使用跳过和限制BUT。

要在有限的文档中进行查询,可以使用特定的索引,例如DATE类型字段上的索引。见下图

let page = ctx.request.body.page || 1
let size = ctx.request.body.size || 10
let DATE_FROM = ctx.request.body.date_from
let DATE_TO = ctx.request.body.date_to

var start = (parseInt(page) - 1) * parseInt(size)

let result = await Model.find({ created_at: { $lte: DATE_FROM, $gte: DATE_TO } })
    .sort({ _id: -1 })
    .select('<fields>')
    .skip( start )
    .limit( size )        
    .exec(callback)

我对这个问题的公认答案感到非常失望。这是无法缩放的。如果你读了游标上的小字。跳过():

cursor.skip()方法通常开销很大,因为它需要服务器从集合或索引的开始处遍历以获得偏移或跳过位置,然后才开始返回结果。随着偏移量(例如上面的pageNumber)的增加,cursor.skip()将变得更慢,更消耗CPU。对于较大的集合,cursor.skip()可能成为IO绑定。

要以可伸缩的方式将limit()与至少一个筛选条件结合起来实现分页,createdOn日期适合多种用途。

MyModel.find( { createdOn: { $lte: request.createdOnBefore } } )
.limit( 10 )
.sort( '-createdOn' )

简单而强大的分页解决方案

async getNextDocs(no_of_docs_required: number = 5, last_doc_id?: string) {
    let docs

    if (!last_doc_id) {
        // get first 5 docs
        docs = await MySchema.find().sort({ _id: -1 }).limit(no_of_docs_required)
    }
    else {
        // get next 5 docs according to that last document id
        docs = await MySchema.find({_id: {$lt: last_doc_id}})
                                    .sort({ _id: -1 }).limit(no_of_docs_required)
    }
    return docs
}

Last_doc_id:您获得的最后一个文档id

No_of_docs_required:你想要获取的文档数量,例如5、10、50等。

如果你不提供last_doc_id给方法,你会得到5个最新的文档 如果你提供了last_doc_id,那么你会得到下一个,即5个文档。