Detta kallas "sändning framåt" vilket är ett koncept som du kan använda för att "effektivt bläddra" igenom resultat i en "framåtriktad" riktning när du använder "sorterade" resultat.
JavaScript-logik ingår (eftersom det fungerar i skalet), men inte svårt att översätta.
Konceptet i allmänhet:
{ "_id": 1, "a": 3 },
{ "_id": 2, "a": 3 },
{ "_id": 3, "a": 3 },
{ "_id": 4, "a": 2 },
{ "_id": 5, "a": 1 },
{ "_id": 6, "a": 0 }
Betrakta de "redan sorterade" dokumenten (för enkelhetens skull) som exempel på resultat som vi vill "sida" med "två" objekt per sida.
I första hand gör du något så här:
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 är de lastVal
och lastSeen
är något du lagrar i något som en "sessionsvariabel" som kan nås vid nästa förfrågan när det gäller webbapplikationer, eller något liknande där inte.
Vad de dock bör innehålla är det allra sista värdet du sorterade på och listan över "unika" _id
värden som sågs eftersom det värdet inte ändrades. Därför:
lastVal = 3,
lastSeen = [1,2];
Poängen är att när begäran om "nästa sida" kommer så vill du använda dessa variabler för något sånt här:
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
});
Vad det gör är att "utesluta" alla värden för _id
som är inspelade i lastSeen
från resultatlistan, samt se till att alla resultat måste vara "mindre än eller lika med" ( fallande ordning ) lastVal
registreras för sorteringsfältet "a".
Detta ger de följande två resultaten i samlingen:
{ "_id": 3, "a": 3 },
{ "_id": 4, "a": 2 },
Men efter att ha bearbetat våra värderingar ser nu ut så här:
lastVal = 2,
lastSeen = [4];
Så nu följer logiken att du inte behöver utesluta det andra _id
värden sett tidigare eftersom du bara verkligen letar efter värden på "a" än som är "mindre än eller lika med" lastVal
och eftersom det bara fanns "ett" _id
värdet som ses vid det värdet utesluter då bara det.
Detta ger naturligtvis nästa sida om att använda samma kod som precis ovan:
{ "_id": 5, "a": 1 },
{ "_id": 6, "a": 0 }
Det är det mest effektiva sättet att "vidarebefordra sida" genom resultat i allmänhet och är särskilt användbart för effektiv sökning av "sorterade" resultat.
Om du däremot vill "hoppa" till sidan 20
eller liknande åtgärd i något skede så är detta inte för dig. Du har fastnat med den traditionella .skip()
och .limit()
tillvägagångssätt för att kunna göra detta med "sidnummer" eftersom det inte finns något annat rationellt sätt att "beräkna" detta.
Så allt beror på hur din applikation implementerar "paging" och vad du kan leva med. .skip()
och .limit()
tillvägagångssättet utsätts för "hoppning" och kan undvikas genom att använda tillvägagångssättet här.
Å andra sidan, om du vill "hoppa till sidan" är "hoppa" ditt enda riktiga alternativ om du inte vill bygga en "cache" av resultat. Men det är en helt annan fråga.