it-swarm.com.de

MongoDB hat die Paginierung erreicht

Es wird gesagt, dass die Verwendung von skip () für die Paginierung in der MongoDB-Sammlung mit vielen Datensätzen langsam ist und nicht empfohlen wird.

Ferne Paginierung (basierend auf> _id-Vergleich) könnte verwendet werden 

db.items.find({_id: {$gt: ObjectId('4f4a3ba2751e88780b000000')}});

Es ist gut für die Anzeige von prev. & next-Schaltflächen - Die Implementierung der Seitenzahlen 1 ... 5 6 7 ... 124 ist jedoch nicht ganz einfach. Sie müssen vorausberechnen, ab welcher "_id" jede Seite beginnt.

Ich habe also zwei Fragen:

1) Wann sollte ich mir Sorgen machen? Wann gibt es "zu viele Datensätze" mit spürbarer Verlangsamung für überspringen ()? 1 000? 1 000 000?

2) Was ist der beste Ansatz, um Links mit tatsächlichen Seitenzahlen anzuzeigen, wenn Sie die Seitenumschaltung verwenden?

65
Roman

Gute Frage!

"Wie viele sind zu viele?" - das hängt natürlich von der Datengröße und den Leistungsanforderungen ab. Ich persönlich fühle mich unwohl, wenn ich mehr als 500-1000 Datensätze überspringe.

Die tatsächliche Antwort hängt von Ihren Anforderungen ab. Hier ist, was moderne Websites tun (oder zumindest einige davon).

Zuerst sieht die Navbar so aus:

1 2 3 ... 457

Sie erhalten die endgültige Seitennummer aus der Gesamtzahl der Datensätze und der Seitengröße. Lassen Sie uns zu Seite 3 springen. Dazu müssen Sie vom ersten Datensatz aus überspringen. Wenn Ergebnisse eintreffen, wissen Sie die ID des ersten Datensatzes auf Seite 3.

1 2 3 4 5 ... 457

Lassen Sie uns etwas mehr überspringen und fahren Sie mit Seite 5 fort.

1 ... 3 4 5 6 7 ... 457

Du hast die Idee. An jedem Punkt sehen Sie die erste, letzte und aktuelle Seite sowie zwei Seiten vor und zurück von der aktuellen Seite.

Anfragen

var current_id; // id of first record on current page.

// go to page current+N
db.collection.find({_id: {$gte: current_id}}).
              skip(N * page_size).
              limit(page_size).
              sort({_id: 1});

// go to page current-N
// note that due to the nature of skipping back,
// this query will get you records in reverse order 
// (last records on the page being first in the resultset)
// You should reverse them in the app.
db.collection.find({_id: {$lt: current_id}}).
              skip((N-1)*page_size).
              limit(page_size).
              sort({_id: -1});
95

Es ist schwierig, eine allgemeine Antwort zu geben, da sie sehr stark davon abhängt, welche Abfrage (oder Abfragen) Sie verwenden, um die angezeigten Ergebnisse zu erstellen. Wenn die Ergebnisse nur über den Index ermittelt werden können und in der Reihenfolge des Indexes dargestellt werden, kann db.dataset.find (). Limit (). Skip () auch mit einer großen Anzahl von Sprüngen eine gute Leistung erbringen. Dies ist wahrscheinlich der einfachste Ansatz zum Code. Aber selbst wenn Sie Seitenzahlen zwischenspeichern und an Indexwerte binden können, können Sie es für die zweite und dritte Person, die beispielsweise Seite 71 anzeigen möchte, schneller machen.

In einem sehr dynamischen Datensatz, in dem Dokumente hinzugefügt und entfernt werden, während ein anderer Benutzer durch die Daten blättert, wird das Zwischenspeichern schnell veraltet und die Limit- und Skip-Methode ist möglicherweise die einzige, die zuverlässig genug ist, um gute Ergebnisse zu erzielen.

6
Tad Marshall

Ich habe vor kurzem dasselbe Problem, wenn ich versuche, eine Anfrage zu paginieren, während ich ein Feld verwende, das nicht eindeutig war, zum Beispiel "FirstName". Die Idee dieser Abfrage besteht darin, die Paginierung in einem nicht eindeutigen Feld implementieren zu können, ohne dabei skip () zu verwenden.

Das Hauptproblem hierbei ist, dass Sie ein Feld abfragen können, das nicht eindeutig "FirstName" ist, da Folgendes eintritt:

  1. $ gt: {"FirstName": "Carlos"} -> dies überspringt alle Datensätze, bei denen der Vorname "Carlos" ist
  2. $ gte: {"FirstName": "Carlos"} -> liefert immer die gleichen Daten

Daher bestand die Lösung, die ich vorschlug, darin, den $ match-Teil der Abfrage eindeutig zu machen, indem das gezielte Suchfeld mit einem sekundären Feld kombiniert wurde, um eine eindeutige Suche zu ermöglichen.

Aufsteigende Reihenfolge:

db.customers.aggregate([
    {$match: { $or: [ {$and: [{'FirstName': 'Carlos'}, {'_id': {$gt: ObjectId("some-object-id")}}]}, {'FirstName': {$gt: 'Carlos'}}]}},
    {$sort: {'FirstName': 1, '_id': 1}},
    {$limit: 10}
    ])

Absteigende Reihenfolge:

db.customers.aggregate([
    {$match: { $or: [ {$and: [{'FirstName': 'Carlos'}, {'_id': {$gt: ObjectId("some-object-id")}}]}, {'FirstName': {$lt: 'Carlos'}}]}},
    {$sort: {'FirstName': -1, '_id': 1}},
    {$limit: 10}
    ])

Der $ match-Teil dieser Abfrage verhält sich im Wesentlichen wie eine if-Anweisung: Wenn firstName "Carlos" ist, muss er auch größer als diese ID sein Wenn firstName nicht "Carlos" ist, muss es größer sein als "Carlos"

Das einzige Problem ist, dass Sie nicht zu einer bestimmten Seitennummer navigieren können (dies ist wahrscheinlich mit einer gewissen Codemanipulation möglich). Das Problem mit der Paginierung für nicht eindeutige Felder wurde jedoch gelöst, ohne dass Sie Skip verwenden mussten, was viel Speicher und Verarbeitung erfordert Leistung, wenn Sie das Ende des Datasets erreichen, nach dem Sie suchen.

1
Carlos Ruiz