Gibt es bei der Verwendung von MongoDB spezielle Muster, um z. B. eine Seitenansicht zu erstellen? Sagen wir ein Blog, das die 10 neuesten Beiträge auflistet, in denen Sie rückwärts zu älteren Beiträgen navigieren können.
Oder löst man es mit einem Index auf zB blogpost.publishdate und überspringt und begrenzt das Ergebnis einfach?
Antworten:
Die Verwendung von skip + limit ist keine gute Möglichkeit, Paging durchzuführen, wenn die Leistung ein Problem darstellt oder wenn große Sammlungen vorhanden sind. Mit zunehmender Seitenzahl wird es immer langsamer. Bei Verwendung von Überspringen muss der Server alle Dokumente (oder Indexwerte) von 0 bis zum Versatzwert (Überspringen) durchlaufen.
Es ist viel besser, eine Bereichsabfrage (+ Limit) zu verwenden, bei der Sie den Bereichswert der letzten Seite übergeben. Wenn Sie beispielsweise nach "Veröffentlichungsdatum" sortieren, übergeben Sie einfach den letzten Wert für "Veröffentlichungsdatum" als Kriterium für die Abfrage, um die nächste Datenseite zu erhalten.
quelle
Mögliche Lösung: Versuchen Sie, das Design zu vereinfachen, und überlegen Sie, ob wir nur nach ID oder einem eindeutigen Wert sortieren können.
Und wenn wir können, kann bereichsbasiertes Pageing verwendet werden.
Die übliche Methode ist die Verwendung von sort (), skip () und limit (), um das oben beschriebene Paging zu implementieren.
quelle
{ _id: { $gt: ... } }
... es funktioniert einfach nicht, wenn benutzerdefinierte Bestellungen verwendet werden - z.sort(...)
.Dies ist die Lösung, die ich verwendet habe, als meine Sammlung zu groß wurde, um in einer einzigen Abfrage zurückgegeben zu werden. Es nutzt die inhärente Reihenfolge des
_id
Felds und ermöglicht es Ihnen, eine Sammlung nach angegebener Stapelgröße zu durchlaufen.Hier ist es als npm-Modul, Mungo-Paging , vollständiger Code ist unten:
function promiseWhile(condition, action) { return new Promise(function(resolve, reject) { process.nextTick(function loop() { if(!condition()) { resolve(); } else { action().then(loop).catch(reject); } }); }); } function findPaged(query, fields, options, iterator, cb) { var Model = this, step = options.step, cursor = null, length = null; promiseWhile(function() { return ( length===null || length > 0 ); }, function() { return new Promise(function(resolve, reject) { if(cursor) query['_id'] = { $gt: cursor }; Model.find(query, fields, options).sort({_id: 1}).limit(step).exec(function(err, items) { if(err) { reject(err); } else { length = items.length; if(length > 0) { cursor = items[length - 1]._id; iterator(items, function(err) { if(err) { reject(err); } else { resolve(); } }); } else { resolve(); } } }); }); }).then(cb).catch(cb); } module.exports = function(schema) { schema.statics.findPaged = findPaged; };
Befestigen Sie es wie folgt an Ihrem Modell:
Dann fragen Sie wie folgt ab:
MyModel.findPaged( // mongoose query object, leave blank for all {source: 'email'}, // fields to return, leave blank for all ['subject', 'message'], // number of results per page {step: 100}, // iterator to call on each set of results function(results, cb) { console.log(results); // this is called repeatedly while until there are no more results. // results is an array of maximum length 100 containing the // results of your query // if all goes well cb(); // if your async stuff has an error cb(err); }, // function to call when finished looping function(err) { throw err; // this is called once there are no more results (err is null), // or if there is an error (then err is set) } );
quelle
Bereichsbasiertes Paging ist machbar, aber Sie müssen klug sein, wie Sie die Abfrage minimieren / maximieren.
Wenn Sie es sich leisten können, sollten Sie versuchen, die Ergebnisse einer Abfrage in einer temporären Datei oder Sammlung zwischenzuspeichern. Dank TTL-Sammlungen in MongoDB können Sie Ihre Ergebnisse in zwei Sammlungen einfügen.
Wenn Sie beide Zusicherungen verwenden, erhalten Sie keine Teilergebnisse, wenn sich die TTL der aktuellen Zeit nähert. Sie können einen einfachen Zähler verwenden, wenn Sie die Ergebnisse speichern, um an diesem Punkt eine SEHR einfache Bereichsabfrage durchzuführen.
quelle
Hier ist ein Beispiel für das Abrufen einer Liste von
User
Dokumenten, die mithilfe des offiziellen C # -Treibers sortiert wurdenCreatedDate
(wobeipageIndex
null basiert).public void List<User> GetUsers() { var connectionString = "<a connection string>"; var client = new MongoClient(connectionString); var server = client.GetServer(); var database = server.GetDatabase("<a database name>"); var sortBy = SortBy<User>.Descending(u => u.CreatedDate); var collection = database.GetCollection<User>("Users"); var cursor = collection.FindAll(); cursor.SetSortOrder(sortBy); cursor.Skip = pageIndex * pageSize; cursor.Limit = pageSize; return cursor.ToList(); }
Alle Sortier- und Paging-Vorgänge werden auf der Serverseite ausgeführt. Obwohl dies ein Beispiel in C # ist, kann das gleiche auch auf andere Sprachports angewendet werden.
Siehe http://docs.mongodb.org/ecosystem/tutorial/use-csharp-driver/#modifying-a-cursor-before-enumerating-it .
quelle
// file:ad-hoc.js // an example of using the less binary as pager in the bash shell // // call on the shell by: // mongo localhost:27017/mydb ad-hoc.js | less // // note ad-hoc.js must be in your current directory // replace the 27017 wit the port of your mongodb instance // replace the mydb with the name of the db you want to query // // create the connection obj conn = new Mongo(); // set the db of the connection // replace the mydb with the name of the db you want to query db = conn.getDB("mydb"); // replace the products with the name of the collection // populate my the products collection // this is just for demo purposes - you will probably have your data already for (var i=0;i<1000;i++ ) { db.products.insert( [ { _id: i, item: "lamp", qty: 50, type: "desk" }, ], { ordered: true } ) } // replace the products with the name of the collection cursor = db.products.find(); // print the collection contents while ( cursor.hasNext() ) { printjson( cursor.next() ); } // eof file: ad-hoc.js
quelle