sql >> Databasteknik >  >> NoSQL >> MongoDB

Implementering av paginering i mongodb

Konceptet du pratar om kan kallas "framåtsökning". En bra anledning till det är till skillnad från att använda .skip() och .limit() modifierare detta kan inte användas för att "gå tillbaka" till en föregående sida eller faktiskt "hoppa" till en specifik sida. Åtminstone inte med en stor ansträngning för att lagra "sedda" eller "upptäckta" sidor, så om den typen av "länkar till sida"-sökning är vad du vill, är det bäst att du håller fast vid .skip() och .limit() tillvägagångssätt, trots prestandanackdelarna.

Om det är ett gångbart alternativ för dig att bara "gå framåt", så här är grundkonceptet:

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 }

Naturligtvis är det din första sida med en gräns på 3 objekt. Tänk på det nu med kod som itererar 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å att itererar markören och gör något, och när det är sant att det sista objektet i markören nås lagrar du lastSeen värde till nuvarande _id :

ObjectId("54c03f0c2f63310180151879")

I dina efterföljande iterationer matar du bara in det _id värde som du behåller ( i session eller vad som helst ) till frågan:

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 }

Och processen upprepas om och om igen tills inga fler resultat kan erhållas.

Det är den grundläggande processen för en naturlig ordning som _id . För något annat blir det lite mer komplicerat. Tänk på följande:

{ "_id": 4, "rank": 3 }
{ "_id": 8, "rank": 3 }
{ "_id": 1, "rank": 3 }    
{ "_id": 3, "rank": 2 }

För att dela upp det i två sidor sorterade efter ranking så är det du egentligen behöver veta vad du "redan har sett" och utesluter dessa resultat. Så tittar på en första sida:

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 }

Vid nästa iteration vill du vara mindre eller lika med "rank"-poängen senast sett, men även exkludera de redan setta dokumenten. Du gör detta 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 }

Hur många "seenIds" du faktiskt håller fast vid beror på hur "granulära" dina resultat är där det värdet sannolikt kommer att förändras. I det här fallet kan du kontrollera om den aktuella "rank"-poängen inte är lika med lastSeen värde och kassera nuvarande seenIds innehåll så att det inte växer för mycket.

Det är de grundläggande koncepten för "sändning framåt" för dig att öva och lära dig.



  1. Importerar JSON-fil med mongimport, fortsätter du att få `oväntad identifierare`?

  2. Sellerifel:result.get timeout

  3. MongoDB $prov

  4. Vad är nytt i MongoDB 4.4