MongoDB Pagination – using $slice
How to implement pagination in MongoDB using $slice
Another technique of implementing pagination in MongoDB involves the use of $push
and $slice
. In this method, we store the documents in an array and use the $slice
method to accomplish what skip()
-and-limit()
does, but without the overhead associated with the skip()
method.
We will be using a single root document in a collection with two fields: i. an array to store the sub-documents, ii. a numerical key to store the size of the array.
// Clear the collection of any previous data and create the root document
db.companies.drop()
db.companies.insert({items:[], count:0})
// Add the sub-documents to the root document
db.companies.update({}, {$push:{items:'Google'}})
db.companies.update({}, {$set:{count:1}})
db.companies.update({}, {$push:{items:'Facebook'}})
db.companies.update({}, {$set:{count:2}})
db.companies.update({}, {$push:{items:'Apple'}})
db.companies.update({}, {$set:{count:3}})
db.companies.update({}, {$push:{items:'Microsoft'}})
db.companies.update({}, {$set:{count:4}})
db.companies.update({}, {$push:{items:'Oracle'}})
db.companies.update({}, {$set:{count:5}})
db.companies.update({}, {$push:{items:'IBM'}})
db.companies.update({}, {$set:{count:6}})
db.companies.update({}, {$push:{items:'Yahoo'}})
db.companies.update({}, {$set:{count:7}})
db.companies.update({}, {$push:{items:'HP'}})
db.companies.update({}, {$set:{count:8}})
Now observe how the $slice
operator works.
db.companies.find({}, {items:{$slice:[0, 3]}})
db.companies.find({}, {items:{$slice:[3, 3]}})
From the above commands you can see, you already have pagination in place. It just needs to be made dynamic, which is accomplished thus:
var skip = NUMBER_OF_ITEMS * (PAGE_NUMBER - 1)
db.companies.find({}, {$slice:[skip, NUMBER_OF_ITEMS]})
NUMBER_OF_ITEMS
is the number of items to be shown on a pagePAGE_NUMBER
is the current page number
For creating the pagination navigation links, use the count
field to get the number of items and the number of pages.
Notes
- Items are no longer root documents
- Need to maintain a count key
- Data structure clarity and logic is somewhat lost
This is great thanks.
I read all three pagination methods you re proposing (using skip, using range and this one), very good tutorials.
The only problem I have in my implementation is that I can’t count results, and I don’t have an autoincresing id. The skip() method seems the only solution to me, but it won’t scale, so it is not a real solution.
In your example, you ‘re counting records when inserting. But what if i have thousands of records, and I wan’t to show a different group each time. For example when I have some tags to filter the results a user needs. I don’t seem to find a way to implement this with the range, or slice method. Am I wrong?
And about how to order the pagination result with slice? Any idea?
I think there’s a mistake.
It should have been:
var skip = NUMBER_OF_ITEMS * (PAGE_NUMBER – 1)
db.companies.find({}, {items:{$slice:[skip, NUMBER_OF_ITEMS]}})