Questa risposta è stata data molto tempo fa e, da allora, MongoDB si è notevolmente evoluto.
Come pubblicato in un'altra risposta, MongoDB ora supporta il campionamento all'interno di Aggregation Framework dalla versione 3.2:
Il modo in cui potresti farlo è:
db.products.aggregate([{$sample: {size: 5}}]); // You want to get 5 docs
Oppure:
db.products.aggregate([
{$match: {category:"Electronic Devices"}}, // filter the results
{$sample: {size: 5}} // You want to get 5 docs
]);
Tuttavia, ci sono alcuni avvisi sull'operatore $sample:
(al 6 novembre 2017, dove l'ultima versione è la 3.4) => Se una di queste condizioni non viene soddisfatta:
- $sample è la prima fase della pipeline
- N è meno del 5% del totale dei documenti nella collezione
- La collezione contiene più di 100 documenti
Se una delle condizioni di cui sopra NON è soddisfatta, $sample esegue una scansione della raccolta seguita da un ordinamento casuale per selezionare N documenti.
Come nell'ultimo esempio con $match
VECCHIA RISPOSTA
Puoi sempre correre:
db.products.find({category:"Electronic Devices"}).skip(Math.random()*YOUR_COLLECTION_SIZE)
Ma l'ordine non sarà casuale e avrai bisogno di due query (un conteggio per ottenere YOUR_COLLECTION_SIZE) o stimare quanto è grande (sono circa 100 record, circa 1000, circa 10000...)
Puoi anche aggiungere un campo a tutti i documenti con un numero casuale e interrogare in base a quel numero. Lo svantaggio qui sarebbe che otterrai gli stessi risultati ogni volta che esegui la stessa query. Per risolvere questo problema puoi sempre giocare con limit e skip o anche con sort. potresti anche aggiornare quei numeri casuali ogni volta che recuperi un record (implica più query).
--Non so se stai usando Mongoose, Mondoid o direttamente Mongo Driver per una lingua specifica, quindi scriverò tutto su mongo shell.
Quindi, diciamo, il tuo record di prodotto sarebbe simile a questo:
{
_id: ObjectId("..."),
name: "Awesome Product",
category: "Electronic Devices",
}
e suggerirei di usare:
{
_id: ObjectId("..."),
name: "Awesome Product",
category: "Electronic Devices",
_random_sample: Math.random()
}
Allora potresti fare:
db.products.find({category:"Electronic Devices",_random_sample:{$gte:Math.random()}})
quindi, potresti eseguire periodicamente in modo da aggiornare periodicamente il campo _random_sample del documento:
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)
o solo ogni volta che recuperi alcuni record puoi aggiornarli tutti o solo alcuni (a seconda di quanti record hai recuperato)
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);
}
MODIFICA
Tieni presente che
db.products.update(your_query,{$set:{_random_sample::Math.random()}},false,true)
non funzionerà molto bene poiché aggiornerà tutti i prodotti che corrispondono alla tua richiesta con lo stesso numero casuale. L'ultimo approccio funziona meglio (aggiornando alcuni documenti man mano che li recuperi)