Isso foi respondido há muito tempo e, desde então, o MongoDB evoluiu muito.
Conforme postado em outra resposta, o MongoDB agora suporta amostragem no Aggregation Framework desde a versão 3.2:
A maneira que você pode fazer isso é:
db.products.aggregate([{$sample: {size: 5}}]); // You want to get 5 docs
Ou:
db.products.aggregate([
{$match: {category:"Electronic Devices"}}, // filter the results
{$sample: {size: 5}} // You want to get 5 docs
]);
No entanto, existem alguns avisos sobre o operador $sample:
(a partir de 6 de novembro de 2017, onde a versão mais recente é 3.4) => Se nada disso for atendido:
- $sample é o primeiro estágio do pipeline
- N é menos de 5% do total de documentos da coleção
- A coleção contém mais de 100 documentos
Se alguma das condições acima NÃO for atendida, $sample executa uma varredura de coleção seguida de uma classificação aleatória para selecionar N documentos.
Como no último exemplo com o $match
RESPOSTA ANTIGA
Você sempre pode executar:
db.products.find({category:"Electronic Devices"}).skip(Math.random()*YOUR_COLLECTION_SIZE)
Mas a ordem não será aleatória e você precisará de duas consultas (uma contagem para obter YOUR_COLLECTION_SIZE) ou estimar o tamanho (são cerca de 100 registros, cerca de 1.000, cerca de 10.000...)
Você também pode adicionar um campo a todos os documentos com um número aleatório e consultar por esse número. A desvantagem aqui seria que você obteria os mesmos resultados toda vez que executar a mesma consulta. Para corrigir isso, você sempre pode jogar com limite e pular ou até mesmo com classificação. você também pode atualizar esses números aleatórios toda vez que buscar um registro (implica mais consultas).
--Eu não sei se você está usando Mongoose, Mondoid ou diretamente o Mongo Driver para qualquer idioma específico, então vou escrever tudo sobre o shell mongo.
Assim, seu registro de produto, digamos, ficaria assim:
{
_id: ObjectId("..."),
name: "Awesome Product",
category: "Electronic Devices",
}
e sugiro usar:
{
_id: ObjectId("..."),
name: "Awesome Product",
category: "Electronic Devices",
_random_sample: Math.random()
}
Então você poderia fazer:
db.products.find({category:"Electronic Devices",_random_sample:{$gte:Math.random()}})
então, você pode executar periodicamente para atualizar o campo _random_sample do documento periodicamente:
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)
ou apenas sempre que você recuperar alguns registros, poderá atualizar todos eles ou apenas alguns (dependendo de quantos registros você recuperou)
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);
}
EDITAR
Esteja ciente que
db.products.update(your_query,{$set:{_random_sample::Math.random()}},false,true)
não funcionará muito bem, pois atualizará todos os produtos que correspondem à sua consulta com o mesmo número aleatório. A última abordagem funciona melhor (atualizando alguns documentos à medida que você os recupera)