MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Implémentation de la pagination dans mongodb

Le concept dont vous parlez peut être appelé « pagination vers l'avant ». Une bonne raison à cela est différente de l'utilisation de .skip() et .limit() modificateurs cela ne peut pas être utilisé pour "revenir" à une page précédente ou même "sauter" à une page spécifique. Du moins pas avec beaucoup d'efforts pour stocker les pages "vues" ou "découvertes", donc si ce type de pagination "liens vers la page" est ce que vous voulez, alors vous feriez mieux de vous en tenir au .skip() et .limit() approche, malgré les inconvénients de performances.

S'il s'agit pour vous d'une option viable consistant uniquement à "avancer", voici le concept de 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 }

Bien sûr, c'est votre première page avec une limite de 3 articles. Considérez cela maintenant avec le code itérant le curseur :

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

Donc, cela itère le curseur et fait quelque chose, et quand il est vrai que le dernier élément du curseur est atteint, vous stockez le lastSeen valeur au présent _id :

ObjectId("54c03f0c2f63310180151879")

Dans vos itérations suivantes, vous alimentez simplement ce _id valeur que vous gardez (en session ou autre) à la requête :

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 }

Et le processus se répète encore et encore jusqu'à ce qu'aucun résultat ne puisse être obtenu.

C'est le processus de base pour un ordre naturel tel que _id . Pour autre chose, cela devient un peu plus complexe. Considérez ce qui suit :

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

Pour diviser cela en deux pages triées par rang, ce que vous devez essentiellement savoir, c'est ce que vous avez "déjà vu" et exclure ces résultats. Alors en regardant une première page :

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 }

À la prochaine itération, vous souhaitez être inférieur ou égal au score de "rang" lastSeen, mais également en excluant les documents déjà vus. Vous faites cela avec le $nin opérateur :

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 }

Le nombre de « seenIds » que vous conservez réellement dépend de la « granularité » de vos résultats là où cette valeur est susceptible de changer. Dans ce cas, vous pouvez vérifier si le score "rank" actuel n'est pas égal au lastSeen value et supprimez les seenIds actuels contenu pour qu'il ne grossisse pas trop.

Ce sont les concepts de base de la « pagination vers l'avant » que vous pouvez pratiquer et apprendre.