Das folgende Rezept ist etwas langsamer als die Lösung aus dem Mongo-Kochbuch (Hinzufügen eines Zufallsschlüssels für jedes Dokument), liefert aber gleichmäßiger verteilte Zufallsdokumente. Es ist etwas ungleichmäßiger verteilt als die skip( random )
Lösung, aber viel schneller und ausfallsicherer für den Fall, dass Dokumente entfernt werden.
function draw(collection, query) {
// query: mongodb query object (optional)
var query = query || { };
query['random'] = { $lte: Math.random() };
var cur = collection.find(query).sort({ rand: -1 });
if (! cur.hasNext()) {
delete query.random;
cur = collection.find(query).sort({ rand: -1 });
}
var doc = cur.next();
doc.random = Math.random();
collection.update({ _id: doc._id }, doc);
return doc;
}
Außerdem müssen Sie Ihren Dokumenten ein Zufallsfeld hinzufügen. Vergessen Sie also nicht, dieses bei der Erstellung der Dokumente hinzuzufügen: Möglicherweise müssen Sie Ihre Sammlung wie von Geoffrey gezeigt initialisieren
function addRandom(collection) {
collection.find().forEach(function (obj) {
obj.random = Math.random();
collection.save(obj);
});
}
db.eval(addRandom, db.things);
Benchmark-Ergebnisse
Diese Methode ist viel schneller als die skip()
Methode (von ceejayoz) und erzeugt gleichmäßigere Zufallsdokumente als die von Michael berichtete "Kochbuch"-Methode:
Für eine Sammlung mit 1.000.000 Elementen:
Die Kochbuch-Methode führt dazu, dass eine große Anzahl von Dokumenten nie ausgewählt wird, weil ihre Zufallszahl sie nicht bevorzugt.
-
Mit dieser Methode werden alle Elemente gleichmäßig über die Zeit erfasst.
-
In meinem Benchmark war sie nur 30 % langsamer als die Kochbuchmethode.
-
die Zufälligkeit ist nicht 100%ig perfekt, aber sehr gut (und sie kann bei Bedarf verbessert werden)
Dieses Rezept ist nicht perfekt - die perfekte Lösung wäre eine eingebaute Funktion, wie andere bereits festgestellt haben.
Für viele Zwecke dürfte es jedoch ein guter Kompromiss sein.