MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Implementazione dell'impaginazione in mongodb

Il concetto di cui stai parlando può essere chiamato "impaginazione in avanti". Un buon motivo è diverso dall'usare .skip() e .limit() modificatori questo non può essere utilizzato per "tornare" a una pagina precedente o addirittura "saltare" a una pagina specifica. Almeno non con un grande sforzo per memorizzare le pagine "viste" o "scoperte", quindi se quel tipo di paginazione "collegamenti alla pagina" è quello che vuoi, allora è meglio attenersi al .skip() e .limit() approccio, nonostante gli svantaggi di prestazioni.

Se è un'opzione praticabile per te solo "andare avanti", ecco il concetto di base:

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 }

Ovviamente questa è la tua prima pagina con un limite di 3 elementi. Consideralo ora con il codice che itera il cursore:

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;
}

In modo che itera il cursore e faccia qualcosa, e quando è vero che viene raggiunto l'ultimo elemento nel cursore memorizzi lastSeen valore al _id attuale :

ObjectId("54c03f0c2f63310180151879")

Nelle tue successive iterazioni dai da mangiare a quel _id valore che mantieni (in sessione o altro) nella query:

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 }

E il processo si ripete più e più volte fino a quando non è possibile ottenere più risultati.

Questo è il processo di base per un ordine naturale come _id . Per qualcos'altro diventa un po' più complesso. Considera quanto segue:

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

Per dividerlo in due pagine ordinate per grado, ciò che devi essenzialmente sapere è ciò che hai "già visto" ed escludere quei risultati. Quindi guardando una prima 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 }

All'iterazione successiva si vuole essere minore o uguale al punteggio "rank" lastSeen, ma anche escludere quelli già visti. Puoi farlo con il $nin operatore:

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 }

Quanti "seenId" ti tieni effettivamente dipende da quanto "granulari" sono i tuoi risultati dove è probabile che quel valore cambi. In questo caso puoi verificare se il punteggio "rank" corrente non è uguale a lastSeen valore e scarta l'attuale seenIds contenuto quindi non cresce molto.

Questi sono i concetti di base del "passaggio in avanti" per esercitarti e imparare.