MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Berechnen Sie den Sprungwert für einen bestimmten Datensatz für sortiertes Paging

Dies wird "Vorwärtsblättern" genannt, ein Konzept, das Sie verwenden können, um "effizient" durch Ergebnisse in einer "Vorwärts"-Richtung zu blättern, wenn Sie "sortierte" Ergebnisse verwenden.

JavaScript-Logik enthalten (weil sie in der Shell funktioniert), aber nicht schwer zu übersetzen.

Das Konzept im Allgemeinen:

{ "_id": 1, "a": 3 },
{ "_id": 2, "a": 3 },
{ "_id": 3, "a": 3 },
{ "_id": 4, "a": 2 },
{ "_id": 5, "a": 1 },
{ "_id": 6, "a": 0 }

Betrachten Sie diese "bereits sortierten" Dokumente (der Einfachheit halber) als Beispiel für Ergebnisse, die wir nach "zwei" Elementen pro Seite "blättern" möchten.

Im ersten Fall machen Sie so etwas:

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

Jetzt diese lastVal und lastSeen sind etwas, das Sie in so etwas wie einer "Sitzungsvariablen" speichern, auf die bei der nächsten Anfrage in Bezug auf Webanwendungen zugegriffen werden kann, oder auf andere Weise etwas Ähnliches, wo dies nicht der Fall ist.

Was sie jedoch enthalten sollten, sind der allerletzte Wert, nach dem Sie sortiert haben, und die Liste der "eindeutigen" _id Werte, die seit diesem Wert gesehen wurden, haben sich nicht geändert. Daher:

lastVal = 3,
lastSeen = [1,2];

Der Punkt ist, dass Sie diese Variablen für etwas wie das Folgende verwenden möchten, wenn die Anfrage für die "nächste Seite" kommt:

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

Das bewirkt, dass alle Werte von _id "ausgeschlossen" werden die in lastSeen aufgezeichnet werden aus der Ergebnisliste und stellen Sie sicher, dass alle Ergebnisse "kleiner oder gleich" (absteigende Reihenfolge) lastVal sein müssen für das Sortierfeld "a" erfasst.

Dies ergibt die nächsten beiden Ergebnisse in der Sammlung:

{ "_id": 3, "a": 3 },
{ "_id": 4, "a": 2 },

Aber nach der Verarbeitung sehen unsere Werte jetzt so aus:

lastVal = 2,
lastSeen = [4];

Nun folgt also die Logik, dass Sie die andere _id nicht ausschließen müssen Werte, die zuvor gesehen wurden, da Sie nur wirklich nach Werten von "a" suchen, die "kleiner oder gleich" dem lastVal sind und da es nur "eine" _id gab Wert, der bei diesem Wert gesehen wird, schließt dann nur diesen aus.

Dies ergibt natürlich die nächste Seite zur Verwendung des gleichen Codes wie oben:

{ "_id": 5, "a": 1 },
{ "_id": 6, "a": 0 }

Dies ist im Allgemeinen die effizienteste Methode, um durch Ergebnisse "vorzublättern", und ist besonders nützlich für das effiziente Blättern von "sortierten" Ergebnissen.

Wenn Sie jedoch auf Seite 20 "springen" möchten oder ähnliche Maßnahmen zu irgendeinem Zeitpunkt, dann ist dies nichts für Sie. Sie bleiben beim traditionellen .skip() hängen und .limit() Ansatz, um dies anhand der "Seitenzahl" tun zu können, da es keinen anderen vernünftigen Weg gibt, dies zu "berechnen".

Es hängt also alles davon ab, wie Ihre Anwendung "Paging" implementiert und womit Sie leben können. Die .skip() und .limit() Der Ansatz leidet unter der Leistung des "Überspringens" und kann vermieden werden, indem der Ansatz hier verwendet wird.

Wenn Sie andererseits "zur Seite springen" möchten, ist "Überspringen" Ihre einzige wirkliche Option, es sei denn, Sie möchten einen "Cache" mit Ergebnissen erstellen. Aber das ist ein ganz anderes Thema.