jpanagiotidis
jpanagiotidis

Reputation: 13

Previous page on MongoDB range query pagination

I have a collection with articles. Because the collection is very big I have to use range queries for pagination (instead of the skip method).
In order to take the first page (of the most recent articles) using a range query on _id its straight forward:

db.articles.find({}, {title:1}).limit(10).sort({_id:-1})

In order to take the next page again is straightforward:

db.articles.find({"_id":{"$lt":ObjectId("43...75")}}, {title:1}).limit(10).sort({_id:-1})

(where the ObjectId is the _id of the last article of the current page)

And here comes the question: "How do i get the PREVIOUS page???"

My first thought was to use the same query using $gt instead of $lt and the _id of the first article of the current page. This however is wrong because if the current page has articles 50-60 the previous page will be 1-10.
In order to overcome this shortcoming, i could sort with sort({_id:1}) and reverse the results array, but i feel it like a hack...

Am I missing something obvious??
Thanks in advance

Upvotes: 1

Views: 2035

Answers (2)

Moksedul Hoque Uzzol
Moksedul Hoque Uzzol

Reputation: 51

I have solved it this way. Please comment if you have any better solution.

// import ObjectId from mongodb
let sortOrder = -1;
let query = []
if (prev) {
    sortOrder = 1
    query.push({title: 'findTitle', _id:{$gt: ObjectId('_idValue')}})
}

if (next) {
    sortOrder = -1
    query.push({title: 'findTitle', _id:{$lt: ObjectId('_idValue')}})
}

db.collection.find(query).limit(10).sort({_id: sortOrder})

Upvotes: 1

wdberkeley
wdberkeley

Reputation: 11671

To paginate with a sort, you remember the highest entry of the previous page in order to return the next 10 results. For example, to paginate on the following collection

> for (var i = 0; i < 100; i++) db.page.insert({ "x" : i })

you do the following

> var page = db.page.find().sort({ "x" : 1 }).limit(10)
// do stuff with the page and get the highest `x`
> var max_x = page.toArray()[9].x
> var next_page = db.page.find({ "x" : { "$gt" : max_x } }).sort({ "x" : 1 }).limit(10)

so there's a mapping max_x => page, i.e. given a max_x you can get the right page since max_x tells you the smallest value of x not on the page. So just remember the previous page's max_x (lower limit of the x for the docs on the page) and you can recall the page.

Upvotes: 0

Related Questions