Следующий рецепт немного медленнее, чем решение монго поваренной книги (добавьте случайный ключ к каждому документу), но возвращает более равномерно распределенные случайные документы.Он немного менее равномерно распределен, чем решение skip( random )
, но гораздо быстрее и надежнее в случае удаления документов.
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;
}
Также требуется добавить случайное "случайное" поле вваши документы, поэтому не забудьте добавить это при создании: вам может потребоваться инициализировать вашу коллекцию, как показано Джеффри
function addRandom(collection) {
collection.find().forEach(function (obj) {
obj.random = Math.random();
collection.save(obj);
});
}
db.eval(addRandom, db.things);
Результаты теста
Этометод намного быстрее, чем метод skip()
(из ceejayoz), и генерирует более равномерно случайные документы, чем метод "поваренной книги", о котором сообщил Майкл:
Для коллекции с 1 000 000 элементов:
Метод поваренной книги приведет к тому, что большое количество документов никогда не будет выбрано, потому что их случайное число не благоприятствует им.
Этот метод будет выбирать все элементы равномерно с течением времени.
В моем тесте он был только на 30% медленнее, чем метод поваренной книги.
случайность не на 100% идеальна, но очень хороша(и при необходимости его можно улучшить)
Этот рецепт не идеален - идеальным решением будет встроенная функция, как отметили другие.
Однако это должно бытьхороший компромисс для многих целей.