Home > Net >  MongoDB returns wrong rows with $sort, $skip and $limit
MongoDB returns wrong rows with $sort, $skip and $limit

Time:11-22

This is the function I'm using

MyModel.aggregate([
  { $match: query },
  { $sort: { 'createdAt': -1 } },
  { $skip: skip },
  { $limit: 10 }
  ], { allowDiskUse : true });

query is to filter the rows. skip is dynamic value based on pagination (i.e 0, 10, 20 ...). The problem is, the rows for each page in wrong. For instance, I can see a specific row in page 1,2,3,4 at the same time! some rows are missing as well.

Why is it happening?

CodePudding user response:

the dynamic value based on pagination (i.e 0, 10, 20 ...) should be used for limit, then the skip should be (page - 1 * limit)

let say,

const limit = 10;
const page = 1;
const skip = (page - 1) * limit; // basically is 0

MyModel.aggregate([
  { $match: query },
  { $sort: { 'createdAt': -1 } },
  { $skip: skip },
  { $limit: limit }
  ], { allowDiskUse : true });

so your query will skip 0 data and start with the first result up 10th

so if you page query is 2,

const limit = 10;
const page = 2;
const skip = (page - 1) * limit; // basically is 10

MyModel.aggregate([
  { $match: query },
  { $sort: { 'createdAt': -1 } },
  { $skip: skip },
  { $limit: limit }
  ], { allowDiskUse : true });

so your query will skip 10 data and start with the 11th result up 20th

CodePudding user response:

I think the key to this question is the information that you shared in this comment:

createdAt for many rows has the same value. is it a probability for $sort not to work properly?

It's not that the sort doesn't "work properly" necessarily, it's that it doesn't have enough information to sort deterministically each time. The value of 123 doesn't come before or after another value of 123 on its own. As @Noel points out, you need to provide an additional field(s) to your sort.

This is also covered here in the documentation:

MongoDB does not store documents in a collection in a particular order. When sorting on a field which contains duplicate values, documents containing those values may be returned in any order.

If consistent sort order is desired, include at least one field in your sort that contains unique values. The easiest way to guarantee this is to include the _id field in your sort query.

This is because the _id field is unique. If you take that approach it would change your sort to:

{ $sort: { 'createdAt': -1, _id: 1 } },
  • Related