Het concept waar je het over hebt kan "forward paging" worden genoemd. Een goede reden daarvoor is in tegenstelling tot het gebruik van .skip()
en .limit()
modifiers dit kan niet worden gebruikt om "terug te gaan" naar een vorige pagina of zelfs "over te slaan" naar een specifieke pagina. In ieder geval niet met veel moeite om "geziene" of "ontdekte" pagina's op te slaan, dus als dat soort "links naar pagina"-pagina's is wat je wilt, dan kun je het beste vasthouden aan de .skip()
en .limit()
aanpak, ondanks de prestatienadelen.
Als het voor jou een haalbare optie is om alleen "vooruit te gaan", dan is hier het basisconcept:
db.junk.find().limit(3)
{ "_id" : ObjectId("54c03f0c2f63310180151877"), "a" : 1, "b" : 1 }
{ "_id" : ObjectId("54c03f0c2f63310180151878"), "a" : 4, "b" : 4 }
{ "_id" : ObjectId("54c03f0c2f63310180151879"), "a" : 10, "b" : 10 }
Dat is natuurlijk je eerste pagina met een limiet van 3 items. Bedenk dat nu met code die de cursor herhaalt:
var lastSeen = null;
var cursor = db.junk.find().limit(3);
while (cursor.hasNext()) {
var doc = cursor.next();
printjson(doc);
if (!cursor.hasNext())
lastSeen = doc._id;
}
Zodat de cursor herhaalt en iets doet, en wanneer het waar is dat het laatste item in de cursor is bereikt, slaat u de lastSeen
op waarde naar de huidige _id
:
ObjectId("54c03f0c2f63310180151879")
In je volgende iteraties voer je gewoon die _id
. in waarde die u (in sessie of wat dan ook) aan de vraag houdt:
var cursor = db.junk.find({ "_id": { "$gt": lastSeen } }).limit(3);
while (cursor.hasNext()) {
var doc = cursor.next();
printjson(doc);
if (!cursor.hasNext())
lastSeen = doc._id;
}
{ "_id" : ObjectId("54c03f0c2f6331018015187a"), "a" : 1, "b" : 1 }
{ "_id" : ObjectId("54c03f0c2f6331018015187b"), "a" : 6, "b" : 6 }
{ "_id" : ObjectId("54c03f0c2f6331018015187c"), "a" : 7, "b" : 7 }
En het proces herhaalt zich keer op keer totdat er geen resultaten meer kunnen worden verkregen.
Dat is het basisproces voor een natuurlijke orde zoals _id
. Voor iets anders wordt het een beetje ingewikkelder. Overweeg het volgende:
{ "_id": 4, "rank": 3 }
{ "_id": 8, "rank": 3 }
{ "_id": 1, "rank": 3 }
{ "_id": 3, "rank": 2 }
Om dat op te splitsen in twee pagina's, gesorteerd op rangorde, moet u in wezen weten wat u "reeds hebt gezien" en die resultaten uitsluiten. Dus kijkend naar een eerste pagina:
var lastSeen = null;
var seenIds = [];
var cursor = db.junk.find().sort({ "rank": -1 }).limit(2);
while (cursor.hasNext()) {
var doc = cursor.next();
printjson(doc);
if ( lastSeen != null && doc.rank != lastSeen )
seenIds = [];
seenIds.push(doc._id);
if (!cursor.hasNext() || lastSeen == null)
lastSeen = doc.rank;
}
{ "_id": 4, "rank": 3 }
{ "_id": 8, "rank": 3 }
Bij de volgende iteratie wil je kleiner of gelijk zijn aan de lastSeen "rank" score, maar ook de reeds bekeken documenten uitsluiten. Dit doe je met de $nin
operator:
var cursor = db.junk.find(
{ "_id": { "$nin": seenIds }, "rank": "$lte": lastSeen }
).sort({ "rank": -1 }).limit(2);
while (cursor.hasNext()) {
var doc = cursor.next();
printjson(doc);
if ( lastSeen != null && doc.rank != lastSeen )
seenIds = [];
seenIds.push(doc._id);
if (!cursor.hasNext() || lastSeen == null)
lastSeen = doc.rank;
}
{ "_id": 1, "rank": 3 }
{ "_id": 3, "rank": 2 }
Hoeveel "seenIds" u daadwerkelijk vasthoudt, hangt af van hoe "granulair" uw resultaten zijn waar die waarde waarschijnlijk zal veranderen. In dit geval kunt u controleren of de huidige "rank"-score niet gelijk is aan de lastSeen
waarde en verwijder de huidige seenIds
inhoud zodat het niet te veel groeit.
Dat zijn de basisconcepten van "forward paging" die u kunt oefenen en leren.