wen tian
wen tian

Reputation: 441

How to implement pagination and total with mongoose

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,
            });
        }
    })
 })

Upvotes: 7

Views: 20245

Answers (3)

Frederiko Ribeiro
Frederiko Ribeiro

Reputation: 2358

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);

Upvotes: 4

Tofazzal haque
Tofazzal haque

Reputation: 569

count() is deprecated(form [email protected]). estimatedDocumentCount() is faster than using countDocuments() for large collections because estimatedDocumentCount() uses collection metadata rather than scanning the entire collection. Reference: https://mongoosejs.com/docs/api/model.html#model_Model.estimatedDocumentCount

So the code is perfect just replace countDocuments to estimatedDocumentCount

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.estimatedDocumentCount(query).exec((count_error, count) => {
        if (err) {
          return res.json(count_error);
        }
        return res.json({
          total: count,
          page: page,
          pageSize: doc.length,
          books: doc
        });
      });
    });
});

Upvotes: 1

Saikat Chakrabortty
Saikat Chakrabortty

Reputation: 2680

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.

Upvotes: 20

Related Questions