How to implement pagination and total with mongoose

13,130

Solution 1

Probably you could do something like this:

Only if current page index is 0 default and pagination starts with next page, that is 1, your could do .skip(page * limit) make sure .skip() and .limit() gets Number.

  router.get("/booksquery", (req, res) => {
  var page = parseInt(req.query.page) || 0; //for next page pass 1 here
  var limit = parseInt(req.query.limit) || 3;
  var query = {};
  Book.find(query)
    .sort({ update_at: -1 })
    .skip(page * limit) //Notice here
    .limit(limit)
    .exec((err, doc) => {
      if (err) {
        return res.json(err);
      }
      Book.countDocuments(query).exec((count_error, count) => {
        if (err) {
          return res.json(count_error);
        }
        return res.json({
          total: count,
          page: page,
          pageSize: doc.length,
          books: doc
        });
      });
    });
});

from above you will get response like below:

 {
  books: [
    {
      _id: 1,
      title: "达·芬奇密码 ",
      author: "[美] 丹·布朗"
    },
    {
      _id: 2,
      title: "梦里花落知多少",
      author: "郭敬明"
    },
    {
      _id: 3,
      title: "红楼梦",
      author: "[清] 曹雪芹"
    }
  ],
  total: 3,
  page: 0,
  pageSize: 3
}

if you use any condition and over that you want to make query and get result and total on that basics. do it inside var query ={} . and the same query will be used for .count() also. so you can get total count on the basics of that condition.

Solution 2

In case someone wants to see this using async/await in 2020, and some random query instead of an empty object. Remember that estimatedDocumentCount does not work using query filters, it needs to be countDocuments by using the query on it. Please check:

  const { userId, page, limit } = req.headers;

  const query = {
    creator: userId,
    status: {
      $nin: ['deleted'],
    },
  };



  const page_ = parseInt(page, 10) || 0;

  const limit_ = parseInt(limit, 10) || 12;

  const books = await BookModel.find(query)
    .sort({ update_at: -1 })
    .skip(page_ * limit_)
    .limit(limit_);

  const count = await BookModel.countDocuments(query);
Share:
13,130
wen tian
Author by

wen tian

Updated on June 09, 2022

Comments

  • wen tian
    wen tian almost 2 years

    I have not found how to return total data included in the resultset. Is there any way to return total data? I need to confirm that the correct JSON data is returned.

    What I want is to have something like this returned:

    total: 40,
    page: 1,
    pageSize: 3,
    books: [
    {
        _id: 1,
        title: "达·芬奇密码 ",
        author: "[美] 丹·布朗",
    },
    {
       _id: 2,
       title: "梦里花落知多少",
       author: "郭敬明",
     },
     {
        _id: 3,
        title: "红楼梦",
        author: "[清] 曹雪芹",
       }
     ]
    }
    

    Current code:

    router.get('/booksquery', (req, res) => {
    
    var page = parseInt(req.query.page) || 1;
    var limit = parseInt(req.query.limit) || 3;
    
    Book.find({})
        .sort({ update_at: -1 })
        .skip((page-1) * limit)
        .limit(limit)
        .exec((err, doc) => {
            if (err) {
                res.json(err)
            } else {
                res.json({
                    total: doc.total,
                    page: page,
                    pageSize: limit,
                    books:doc,
                });
            }
        })
     })