На това беше отговорено много отдавна и оттогава MongoDB значително се е развил.
Както е публикувано в друг отговор, MongoDB вече поддържа вземане на проби в рамките на Aggregation Framework от версия 3.2:
Начинът, по който можете да направите това е:
db.products.aggregate([{$sample: {size: 5}}]); // You want to get 5 docs
Или:
db.products.aggregate([
{$match: {category:"Electronic Devices"}}, // filter the results
{$sample: {size: 5}} // You want to get 5 docs
]);
Има обаче някои предупреждения относно оператора $sample:
(от 6 ноември 2017 г., където последната версия е 3.4) => Ако нещо от това не е изпълнено:
- $sample е първият етап от конвейера
- N е по-малко от 5% от общия брой документи в колекцията
- Колекцията съдържа повече от 100 документа
Ако някое от горните условия НЕ е изпълнено, $sample извършва сканиране на колекция, последвано от произволно сортиране, за да избере N документа.
Както в последния пример с $match
СТАР ОТГОВОР
Винаги можете да стартирате:
db.products.find({category:"Electronic Devices"}).skip(Math.random()*YOUR_COLLECTION_SIZE)
Но редът няма да е произволен и ще ви трябват две заявки (едно броене, за да получите YOUR_COLLECTION_SIZE) или преценете колко голям е (това е около 100 записа, около 1000, около 10000...)
Можете също да добавите поле към всички документи с произволен номер и да направите заявка по този номер. Недостатъкът тук би бил, че ще получавате същите резултати всеки път, когато изпълнявате една и съща заявка. За да коригирате това, винаги можете да играете с лимит и пропускане или дори със сортиране. бихте могли също да актуализирате тези произволни числа всеки път, когато извличате запис (предполага повече заявки).
--Не знам дали използвате Mongoose, Mondoid или директно Mongo Driver за конкретен език, така че ще напиша всичко за mongo shell.
Така вашият, да кажем, продуктов запис ще изглежда така:
{
_id: ObjectId("..."),
name: "Awesome Product",
category: "Electronic Devices",
}
и бих предложил да използвате:
{
_id: ObjectId("..."),
name: "Awesome Product",
category: "Electronic Devices",
_random_sample: Math.random()
}
Тогава можете да направите:
db.products.find({category:"Electronic Devices",_random_sample:{$gte:Math.random()}})
след това можете да изпълнявате периодично, така че периодично да актуализирате полето _random_sample на документа:
var your_query = {} //it would impact in your performance if there are a lot of records
your_query = {category: "Electronic Devices"} //Update
//upsert = false, multi = true
db.products.update(your_query,{$set:{_random_sample::Math.random()}},false,true)
или просто всеки път, когато извлечете някои записи, можете да актуализирате всички или само няколко (в зависимост от това колко записа сте изтеглили)
for(var i = 0; i < records.length; i++){
var query = {_id: records[i]._id};
//upsert = false, multi = false
db.products.update(query,{$set:{_random_sample::Math.random()}},false,false);
}
РЕДАКТИРАНЕ
Имайте предвид, че
db.products.update(your_query,{$set:{_random_sample::Math.random()}},false,true)
няма да работи много добре, тъй като ще актуализира всички продукти, които отговарят на вашата заявка, с същите произволно число. Последният подход работи по-добре (актуализиране на някои документи, докато ги извличате)