Odpowiedź została udzielona dawno temu i od tego czasu MongoDB znacznie się rozwinęło.
Jak opublikowano w innej odpowiedzi, MongoDB obsługuje teraz próbkowanie w ramach agregacji od wersji 3.2:
Sposób, w jaki możesz to zrobić, to:
db.products.aggregate([{$sample: {size: 5}}]); // You want to get 5 docs
Lub:
db.products.aggregate([
{$match: {category:"Electronic Devices"}}, // filter the results
{$sample: {size: 5}} // You want to get 5 docs
]);
Istnieje jednak kilka ostrzeżeń dotyczących operatora $sample:
(stan na 6 listopada 2017 r., gdzie najnowsza wersja to 3.4) => Jeśli którykolwiek z tych warunków nie jest spełniony:
- $samp to pierwszy etap potoku
- N to mniej niż 5% wszystkich dokumentów w kolekcji
- Zbiór zawiera ponad 100 dokumentów
Jeśli którykolwiek z powyższych warunków NIE jest spełniony, $sample wykonuje skanowanie kolekcji, a następnie losowe sortowanie w celu wybrania N dokumentów.
Jak w ostatnim przykładzie z $match
STARA ODPOWIEDŹ
Zawsze możesz uruchomić:
db.products.find({category:"Electronic Devices"}).skip(Math.random()*YOUR_COLLECTION_SIZE)
Ale kolejność nie będzie losowa i będziesz potrzebować dwóch zapytań (jedno zliczanie, aby uzyskać YOUR_COLLECTION_SIZE) lub oszacować jego wielkość (około 100 rekordów, około 1000, około 10000...)
Możesz również dodać pole do wszystkich dokumentów z losową liczbą i zapytaniem według tej liczby. Wadą byłoby to, że za każdym razem, gdy uruchomisz to samo zapytanie, otrzymasz te same wyniki. Aby to naprawić, zawsze możesz grać z limitem i pomijać lub nawet sortować. równie dobrze możesz aktualizować te liczby losowe za każdym razem, gdy pobierasz rekord (co oznacza więcej zapytań).
--Nie wiem, czy używasz Mongoose, Mondoid czy bezpośrednio Mongo Driver dla konkretnego języka, więc napiszę wszystko o powłoce Mongo.
Tak więc, powiedzmy, rekord produktu będzie wyglądał tak:
{
_id: ObjectId("..."),
name: "Awesome Product",
category: "Electronic Devices",
}
i proponuję użyć:
{
_id: ObjectId("..."),
name: "Awesome Product",
category: "Electronic Devices",
_random_sample: Math.random()
}
Wtedy możesz zrobić:
db.products.find({category:"Electronic Devices",_random_sample:{$gte:Math.random()}})
wtedy możesz uruchamiać okresowo, aby okresowo aktualizować pole _random_sample dokumentu:
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)
lub po prostu za każdym razem, gdy pobierasz jakieś rekordy, możesz zaktualizować je wszystkie lub tylko kilka (w zależności od tego, ile rekordów pobrałeś)
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);
}
EDYTUJ
Należy pamiętać, że
db.products.update(your_query,{$set:{_random_sample::Math.random()}},false,true)
nie będzie działać zbyt dobrze, ponieważ zaktualizuje wszystkie produkty pasujące do zapytania z takim samym Liczba losowa. Ostatnie podejście działa lepiej (aktualizacja niektórych dokumentów podczas ich pobierania)