Dette kaldes "forward paging", som er et koncept, du kan bruge til at "effektivt bladre" gennem resultater i en "fremad" retning, når du bruger "sorterede" resultater.
JavaScript-logik inkluderet (fordi det virker i skallen), men ikke svært at oversætte.
Konceptet generelt:
{ "_id": 1, "a": 3 },
{ "_id": 2, "a": 3 },
{ "_id": 3, "a": 3 },
{ "_id": 4, "a": 2 },
{ "_id": 5, "a": 1 },
{ "_id": 6, "a": 0 }
Betragt disse "allerede sorterede" dokumenter (for nemheds skyld) som et eksempel på resultater, vi ønsker at "side" med "to" elementer pr. side.
I første omgang gør du sådan noget:
var lastVal = null,
lastSeen = [];
db.collection.find().sort({ "a": -1 }).limit(2).forEach(function(doc) {
if ( lastVal != doc.a ) {
lastSeen = [];
}
lastVal = doc.a;
lastSeen.push( doc._id );
// do something useful with each document matched
});
Nu de lastVal
og lastSeen
er noget, du gemmer i noget som en "sessionsvariabel", end der kan tilgås ved næste anmodning i form af webapplikationer, eller på anden måde noget lignende, hvor ikke.
Hvad de dog skal indeholde er den allersidste værdi, du sorterede efter, og listen over "unik" _id
værdier, der blev set, da denne værdi ikke ændrede sig. Derfor:
lastVal = 3,
lastSeen = [1,2];
Pointen er, at når anmodningen om den "næste side" kommer omkring, så vil du bruge disse variabler til noget som dette:
var lastVal = 3,
lastSeen = [1,2];
db.collection.find({
"_id": { "$nin": lastSeen },
"a": { "$lte": lastVal }
}).sort({ "a": -1 }).limit(2).forEach(function(doc) {
if ( lastVal != doc.a ) {
lastSeen = [];
}
lastVal = doc.a;
lastSeen.push( doc._id );
// do something useful with each document matched
});
Det, der gør, er at "udelukke" alle værdier af _id
der er optaget i lastSeen
fra listen over resultater, samt sørg for, at alle resultater skal være "mindre end eller lig med" ( faldende rækkefølge) lastVal
registreret for sorteringsfeltet "a".
Dette giver de næste to resultater i samlingen:
{ "_id": 3, "a": 3 },
{ "_id": 4, "a": 2 },
Men efter at have behandlet vores værdier ser nu sådan ud:
lastVal = 2,
lastSeen = [4];
Så nu følger logikken, at du ikke behøver at udelukke den anden _id
værdier set før, da du kun virkelig leder efter værdier af "a", end der er "mindre end eller lig med" lastVal
og da der kun var "én" _id
værdi, der ses ved den værdi, udelukker så kun den.
Dette giver naturligvis den næste side om at bruge den samme kode som lige ovenfor:
{ "_id": 5, "a": 1 },
{ "_id": 6, "a": 0 }
Det er den mest effektive måde at "fremsende side" gennem resultater generelt og er især nyttig til effektiv sidesøgning af "sorterede" resultater.
Hvis du imidlertid vil "springe" til side 20
eller lignende handling på noget tidspunkt, så er dette ikke noget for dig. Du sidder fast med den traditionelle .skip()
og .limit()
tilgang til at kunne gøre dette ved "sidetal", da der ikke er nogen anden rationel måde at "beregne" dette på.
Så det hele afhænger af, hvordan din applikation implementerer "paging", og hvad du kan leve med. .skip()
og .limit()
tilgang lider under udførelsen af "spring" og kan undgås ved at bruge fremgangsmåden her.
På den anden side, hvis du vil "springe til side", så er "spring" din eneste rigtige mulighed, medmindre du vil opbygge en "cache" af resultater. Men det er et helt andet problem.