¿Cómo puedo obtener un registro aleatorio de MongoDB?
Estoy buscando obtener un registro aleatorio de una colección enorme (100 millones de registros).
¿Cuál es la forma más rápida y eficiente de hacerlo?
Los datos ya están ahí y no hay ningún campo en el que pueda generar un número aleatorio y obtener una fila aleatoria.
A partir de la versión 3.2 de MongoDB, puede obtener N documentos aleatorios de una colección utilizando el $sample
operador de canalización de agregación:
// Get one random document from the mycoll collection.
db.mycoll.aggregate([{ $sample: { size: 1 } }])
Si desea seleccionar los documentos aleatorios de un subconjunto filtrado de la colección, anteponga una $match
etapa a la canalización:
// Get one random document matching {a: 10} from the mycoll collection.
db.mycoll.aggregate([
{ $match: { a: 10 } },
{ $sample: { size: 1 } }
])
Como se indica en los comentarios, cuando size
es mayor que 1, puede haber duplicados en la muestra del documento devuelto.
Haga un recuento de todos los registros, genere un número aleatorio entre 0 y el recuento y luego haga:
db.yourCollection.find().limit(-1).skip(yourRandomNumber).next()
Actualización para MongoDB 3.2
3.2 introdujo $sample en el canal de agregación.
También hay una buena publicación de blog sobre cómo ponerlo en práctica.
Para versiones anteriores (respuesta anterior)
En realidad, se trataba de una solicitud de función: http://jira.mongodb.org/browse/SERVER-533 , pero se archivó en "No se solucionará".
El libro de cocina tiene una muy buena receta para seleccionar un documento aleatorio de una colección: http://cookbook.mongodb.org/patterns/random-attribute/
Parafraseando la receta, asigna números aleatorios a sus documentos:
db.docs.save( { key : 1, ..., random : Math.random() } )
Luego seleccione un documento aleatorio:
rand = Math.random()
result = db.docs.findOne( { key : 2, random : { $gte : rand } } )
if ( result == null ) {
result = db.docs.findOne( { key : 2, random : { $lte : rand } } )
}
Consultando con ambos $gte
es $lte
necesario encontrar el documento con un número aleatorio más cercano rand
.
Y, por supuesto, querrás indexar en el campo aleatorio:
db.docs.ensureIndex( { key : 1, random :1 } )
Si ya está consultando un índice, simplemente suéltelo, agréguelo random: 1
y agréguelo nuevamente.
También puede utilizar la función de indexación geoespacial de MongoDB para seleccionar los documentos "más cercanos" a un número aleatorio.
Primero, habilite la indexación geoespacial en una colección:
db.docs.ensureIndex( { random_point: '2d' } )
Para crear un conjunto de documentos con puntos aleatorios en el eje X:
for ( i = 0; i < 10; ++i ) {
db.docs.insert( { key: i, random_point: [Math.random(), 0] } );
}
Luego puedes obtener un documento aleatorio de la colección como este:
db.docs.findOne( { random_point : { $near : [Math.random(), 0] } } )
O puedes recuperar varios documentos más cercanos a un punto aleatorio:
db.docs.find( { random_point : { $near : [Math.random(), 0] } } ).limit( 4 )
Esto requiere solo una consulta y no verificaciones nulas, además el código es limpio, simple y flexible. Incluso podrías usar el eje Y del geopunto para agregar una segunda dimensión de aleatoriedad a tu consulta.