MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

MongoDB:como encontrar 10 documentos aleatórios em uma coleção de 100?


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)