En MongoDB, el $rand
El operador de canalización de agregación devuelve un flotante aleatorio entre 0 y 1.
El valor de punto flotante tiene hasta 17 dígitos después del punto decimal. Los ceros finales se eliminan, por lo que la cantidad de dígitos puede variar.
El $rand
El operador se introdujo en MongoDB 4.4.2.
Ejemplo
Supongamos que tenemos una colección llamada cats
con los siguientes documentos:
{ "_id" : 1, "name" : "Scratch" } { "_id" : 2, "name" : "Meow" } { "_id" : 3, "name" : "Fluffy" }
Podemos usar el $rand
operador para generar un número aleatorio para cada gato:
db.cats.aggregate(
[
{
$project:
{
randomNumber: { $rand: {} }
}
}
]
)
Resultado:
{ "_id" : 1, "randomNumber" : 0.5593964875463812 } { "_id" : 2, "randomNumber" : 0.04357301703691149 } { "_id" : 3, "randomNumber" : 0.7556877215199272 }
El $rand
El operador no acepta ningún argumento; simplemente lo llama usando $rand: {}
.
Además, $rand
genera un nuevo número cada vez que se llama. Por lo tanto, ejecutar el código anterior varias veces generará un número aleatorio diferente para cada gato.
Solo para demostrar esto, lo ejecutaré de nuevo y aquí está el nuevo resultado:
{ "_id" : 1, "randomNumber" : 0.19672627212049873 } { "_id" : 2, "randomNumber" : 0.05513133909795318 } { "_id" : 3, "randomNumber" : 0.7509841462815067 }
Podemos ver que los números aleatorios son diferentes a los generados en el ejemplo anterior.
Números aleatorios mayores que 1
Como se mencionó, $rand
devuelve un flotante aleatorio entre 0 y 1. Esto está bien si no nos importa obtener un cero, seguido de hasta 17 decimales aleatorios.
Pero, ¿y si queremos un número aleatorio mayor que 1?
En tales casos, podemos usar el $multiply
operador para multiplicar el resultado de $rand
.
Ejemplo:
db.cats.aggregate(
[
{
$project:
{
randomNumber: { $multiply: [ { $rand: {} }, 10 ] }
}
}
]
)
Resultado:
{ "_id" : 1, "randomNumber" : 1.958938543288535 } { "_id" : 2, "randomNumber" : 4.437057321655847 } { "_id" : 3, "randomNumber" : 8.238909118372334 }
Entero aleatorio
También podríamos querer eliminar la parte fraccionaria. En este caso, podemos usar un operador como $floor
para eliminar la parte decimal, dejando así un número entero.
Ejemplo:
db.cats.aggregate(
[
{
$project:
{
name: 1,
randomNumber: {
$floor: {
$multiply: [ { $rand: {} }, 10 ]
}
}
}
}
]
)
Resultado:
{ "_id" : 1, "name" : "Scratch", "randomNumber" : 0 } { "_id" : 2, "name" : "Meow", "randomNumber" : 5 } { "_id" : 3, "name" : "Fluffy", "randomNumber" : 7 }
Aquí está de nuevo, pero esta vez lo multiplicamos por 100:
db.cats.aggregate(
[
{
$project:
{
name: 1,
randomNumber: {
$floor: {
$multiply: [ { $rand: {} }, 100 ]
}
}
}
}
]
)
Resultado:
{ "_id" : 1, "name" : "Scratch", "randomNumber" : 18 } { "_id" : 2, "name" : "Meow", "randomNumber" : 62 } { "_id" : 3, "name" : "Fluffy", "randomNumber" : 92 }
Guardar los resultados
Como se mencionó, $rand
genera un nuevo flotante aleatorio cada vez que se llama. Esto está bien si queremos un nuevo número aleatorio cada vez que ejecutamos el código, pero ¿qué sucede si queremos almacenar el número aleatorio en cada documento?
Para almacenar el número aleatorio en el documento, podemos usar $addFields
operador (o su alias $set
) para agregar el nuevo campo al documento.
Ejemplo:
db.cats.aggregate(
[
{ $set: { randomNumber: { $multiply: [ { $rand: {} }, 100 ] } } },
{ $set: { randomNumber: { $floor: "$randomNumber" } } },
{ $merge: "cats" }
]
)
En este ejemplo, separamos la operación en dos $set
etapas y un $merge
escenario.
El $merge
etapa escribe los resultados de la tubería de agregación en una colección específica, y debe ser la última etapa de la tubería.
Ahora, cuando devolvemos los documentos de esa colección (por ejemplo, usando un método como find()
), podemos ver que cada documento contiene el nuevo campo con el número aleatorio:
db.cats.find()
Resultado:
{ "_id" : 1, "name" : "Scratch", "randomNumber" : 61 } { "_id" : 2, "name" : "Meow", "randomNumber" : 86 } { "_id" : 3, "name" : "Fluffy", "randomNumber" : 73 }
Ahora el número aleatorio es persistente. Podemos devolver los documentos tantas veces como queramos y el número aleatorio seguirá siendo el mismo.
Ejecutemos find()
de nuevo:
db.cats.find()
Resultado:
{ "_id" : 1, "name" : "Scratch", "randomNumber" : 61 } { "_id" : 2, "name" : "Meow", "randomNumber" : 86 } { "_id" : 3, "name" : "Fluffy", "randomNumber" : 73 }
Exactamente el mismo número aleatorio.