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


当前回答

您可以使用skip()和limit(),但效率非常低。更好的解决方案是对索引字段加上limit()进行排序。 我们在Wunderflats发布了一个小库:https://github.com/wunderflats/goosepage 它用了第一种方法。

其他回答

查询:

search = productName

参数:

page = 1 

// Pagination
router.get("/search/:page", (req, res, next) => {
    const resultsPerPage = 5;
    let page = req.params.page >= 1 ? req.params.page : 1;
    const query = req.query.search;

    page = page - 1

    Product.find({ name: query })
        .select("name")
        .sort({ name: "asc" })
        .limit(resultsPerPage)
        .skip(resultsPerPage * page)
        .then((results) => {
            return res.status(200).send(results);
        })
        .catch((err) => {
            return res.status(500).send(err);
        });
});

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

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个文档。

app.get("/:page",(req,res)=>{
        post.find({}).then((data)=>{
            let per_page = 5;
            let num_page = Number(req.params.page);
            let max_pages = Math.ceil(data.length/per_page);
            if(num_page == 0 || num_page > max_pages){
                res.render('404');
            }else{
                let starting = per_page*(num_page-1)
                let ending = per_page+starting
                res.render('posts', {posts:data.slice(starting,ending), pages: max_pages, current_page: num_page});
            }
        });
});
const ITEMS_PER_PAGE = 2;

exports.getProducts = (req, res, next) => {
  // + will turn the string to a number
  const page = +req.query.page || 1;
  let totalItems;
  //Product model
  Product.find()
    .countDocuments()
    .then((numProducts) => {
      totalItems = numProducts;
      return Product.find()
         //If query param is 3, since ITEMS_PER_PAGE = 2, we skip 2*2 items   
         // we show only 5th and 6th item
        .skip((page - 1) * ITEMS_PER_PAGE)
        .limit(ITEMS_PER_PAGE);
    })
    .then((products) => {
      res.render("shop/products", {
        // maybe sending the products object to templating engine
      });
    })
    .catch((err) => {
      const error = new Error(err);
      error.httpStatusCode = 500;
      // if you are set express error handler, use this
      // when we call next() with an argument passed in, we let express know, we skip all other middlewares, we move to error handling middleware

      return next(error);
    });
};

有一些很好的答案给出了使用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 => {

  })