Konceptet du taler om kan kaldes "forward paging". En god grund til det er i modsætning til at bruge .skip()
og .limit()
modifikatorer dette kan ikke bruges til at "gå tilbage" til en tidligere side eller faktisk "springe over" til en bestemt side. I hvert fald ikke med en stor indsats for at gemme "sete" eller "opdagede" sider, så hvis den type "links til side"-sidesøgning er, hvad du ønsker, så er det bedst at du holder dig til .skip()
og .limit()
tilgang på trods af præstationsmanglerne.
Hvis det er en farbar mulighed for dig kun at "gå fremad", så er her det grundlæggende koncept:
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 }
Det er selvfølgelig din første side med en grænse på 3 elementer. Overvej det nu med kode, der gentager markøren:
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;
}
Så det gentager markøren og gør noget, og når det er sandt, at det sidste punkt i markøren er nået, gemmer du lastSeen
værdi til det nuværende _id
:
ObjectId("54c03f0c2f63310180151879")
I dine efterfølgende iterationer fodrer du bare det _id
værdi, som du beholder (i session eller hvad som helst) til forespørgslen:
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 }
Og processen gentages igen og igen, indtil der ikke kan opnås flere resultater.
Det er den grundlæggende proces for en naturlig orden såsom _id
. For noget andet bliver det lidt mere komplekst. Overvej følgende:
{ "_id": 4, "rank": 3 }
{ "_id": 8, "rank": 3 }
{ "_id": 1, "rank": 3 }
{ "_id": 3, "rank": 2 }
For at opdele det i to sider sorteret efter rangering, så er det, du i bund og grund har brug for at vide, hvad du "allerede har set" og udelukker disse resultater. Så ser på en første side:
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 }
Ved den næste iteration vil du være mindre eller lig med den sidst sete "rangering", men også ekskludere de allerede sete dokumenter. Du gør dette med $nin
operatør:
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 }
Hvor mange "seenIds" du rent faktisk holder på afhænger af, hvor "granulære" dine resultater er, hvor værdien sandsynligvis vil ændre sig. I dette tilfælde kan du kontrollere, om den aktuelle "rang"-score ikke er lig med lastSeen
værdi og kasser de nuværende seenIds
indhold, så det ikke vokser for meget.
Det er de grundlæggende begreber for "fremadsøgning", som du kan øve dig på og lære.