En MongoDB, el $range
El operador de canalización de agregación devuelve una secuencia generada de números en una matriz.
Esta secuencia de números se basa en los valores de entrada que proporcione.
Sintaxis
La sintaxis es así:
{ $range: [ <start>, <end>, <non-zero step> ] }
Donde <start>
es el inicio y <end>
es el final de la secuencia. Cada uno de estos puede ser cualquier expresión válida que se resuelva en un número entero.
<non-zero step>
es un argumento opcional cuyo valor predeterminado es 1. Este argumento le permite especificar un valor de incremento. Si se proporciona, debe ser una expresión válida que se resuelva en un número entero distinto de cero.
Ejemplo
Supongamos que tenemos una colección llamada range
con los siguientes documentos:
{ "_id" : 1, "start" : 0, "end" : 5 } { "_id" : 2, "start" : 1, "end" : 5 }
Podemos usar el $range
operador para devolver una matriz basada en los valores de esos documentos.
db.range.aggregate(
[
{ $match: { _id: { $in: [ 1, 2 ] } } },
{
$project:
{
_id: 0,
start: 1,
end: 1,
result: { $range: [ "$start", "$end" ] }
}
}
]
)
Resultado:
{ "start" : 0, "end" : 5, "result" : [ 0, 1, 2, 3, 4 ] } { "start" : 1, "end" : 5, "result" : [ 1, 2, 3, 4 ] }
En este caso, no proporcionamos un tercer argumento, por lo que $range
usa su valor de paso predeterminado de 1. Por lo tanto, los elementos de la matriz se incrementan en 1.
Añadir un incremento explícito
Podemos agregar un tercer argumento para especificar explícitamente cuánto debe incrementarse cada elemento de la matriz.
Supongamos que nuestra colección contiene los siguientes documentos:
{ "_id" : 3, "start" : 0, "end" : 5, "step" : 1 } { "_id" : 4, "start" : 0, "end" : 10, "step" : 2 } { "_id" : 5, "start" : 1, "end" : 10, "step" : 2 } { "_id" : 6, "start" : 100, "end" : 150, "step" : 10 }
Estos documentos tienen un step
campo, por lo que podemos usar ese campo para el valor incremental para el documento respectivo.
Ahora apliquemos $range
a esos documentos e incluir el step
campo como tercer argumento:
db.range.aggregate(
[
{ $match: { _id: { $in: [ 3, 4, 5, 6 ] } } },
{
$project:
{
_id: 0,
start: 1,
end: 1,
step: 1,
result: { $range: [ "$start", "$end", "$step" ] }
}
}
]
)
Resultado:
{ "start" : 0, "end" : 5, "step" : 1, "result" : [ 0, 1, 2, 3, 4 ] } { "start" : 0, "end" : 10, "step" : 2, "result" : [ 0, 2, 4, 6, 8 ] } { "start" : 1, "end" : 10, "step" : 2, "result" : [ 1, 3, 5, 7, 9 ] } { "start" : 100, "end" : 150, "step" : 10, "result" : [ 100, 110, 120, 130, 140 ] }
Valores de paso negativos
El paso puede ser un valor negativo, aunque esto debe hacerse en el contexto de la disminución desde un start
más alto número a un end
más bajo número.
Agreguemos algunos documentos más a nuestra colección:
{ "_id" : 7, "start" : 0, "end" : 5, "step" : -1 } { "_id" : 8, "start" : 5, "end" : 0, "step" : -1 } { "_id" : 9, "start" : 0, "end" : -5, "step" : -1 }
Ahora apliquemos $range
a esos documentos:
db.range.aggregate(
[
{ $match: { _id: { $in: [ 7, 8, 9 ] } } },
{
$project:
{
_id: 0,
start: 1,
end: 1,
step: 1,
result: { $range: [ "$start", "$end", "$step" ] }
}
}
]
)
Resultado:
{ "start" : 0, "end" : 5, "step" : -1, "result" : [ ] } { "start" : 5, "end" : 0, "step" : -1, "result" : [ 5, 4, 3, 2, 1 ] } { "start" : 0, "end" : -5, "step" : -1, "result" : [ 0, -1, -2, -3, -4 ] }
Podemos ver que el primer documento devolvió una matriz vacía porque el valor del paso negativo está fuera del rango proporcionado por start
y end
campos.
Sin embargo, los documentos posteriores produjeron un rango decreciente de valores.
Cuando el paso es cero
El valor del paso debe ser un número entero distinto de cero. Proporcionar un paso de 0
devuelve un error.
Supongamos que agregamos el siguiente documento a nuestra colección:
{ "_id" : 10, "start" : 1, "end" : 5, "step" : 0 }
Esto es lo que sucede cuando aplicamos $range
a ese documento:
db.range.aggregate(
[
{ $match: { _id: { $in: [ 10 ] } } },
{
$project:
{
_id: 0,
start: 1,
end: 1,
result: { $range: [ "$start", "$end", "$step" ] }
}
}
]
)
Resultado:
uncaught exception: Error: command failed: { "ok" : 0, "errmsg" : "$range requires a non-zero step value", "code" : 34449, "codeName" : "Location34449" } : aggregate failed : [email protected]/mongo/shell/utils.js:25:13 [email protected]/mongo/shell/assert.js:18:14 [email protected]/mongo/shell/assert.js:639:17 [email protected]/mongo/shell/assert.js:729:16 [email protected]/mongo/shell/db.js:266:5 [email protected]/mongo/shell/collection.js:1058:12 @(shell):1:1
El mensaje de error nos dice explícitamente que $range requires a non-zero step value
.
Pasos nulos
El paso no puede ser null
tampoco.
Supongamos que tenemos el siguiente documento:
{ "_id" : 11, "start" : 1, "end" : 5, "step" : null }
Y aplicamos $range
a ello:
db.range.aggregate(
[
{ $match: { _id: { $in: [ 11 ] } } },
{
$project:
{
_id: 0,
start: 1,
end: 1,
result: { $range: [ "$start", "$end", "$step" ] }
}
}
]
)
Resultado:
uncaught exception: Error: command failed: { "ok" : 0, "errmsg" : "$range requires a numeric step value, found value of type:null", "code" : 34447, "codeName" : "Location34447" } : aggregate failed : [email protected]/mongo/shell/utils.js:25:13 [email protected]/mongo/shell/assert.js:18:14 [email protected]/mongo/shell/assert.js:639:17 [email protected]/mongo/shell/assert.js:729:16 [email protected]/mongo/shell/db.js:266:5 [email protected]/mongo/shell/collection.js:1058:12 @(shell):1:1
Esto nos dice que $range requires a numeric step value, found value of type:null
.
Rangos nulos
Si el start
y/o end
los campos son null
, luego se devuelve un error.
Supongamos que tenemos el siguiente documento:
{ "_id" : 11, "start" : 1, "end" : 5, "step" : null }
Y aplica $range
a ello:
db.range.aggregate(
[
{ $match: { _id: { $in: [ 11 ] } } },
{
$project:
{
_id: 0,
start: 1,
end: 1,
result: { $range: [ "$start", "$end", "$step" ] }
}
}
]
)
Resultado:
uncaught exception: Error: command failed: { "ok" : 0, "errmsg" : "$range requires a numeric starting value, found value of type: null", "code" : 34443, "codeName" : "Location34443" } : aggregate failed : [email protected]/mongo/shell/utils.js:25:13 [email protected]/mongo/shell/assert.js:18:14 [email protected]/mongo/shell/assert.js:639:17 [email protected]/mongo/shell/assert.js:729:16 [email protected]/mongo/shell/db.js:266:5 [email protected]/mongo/shell/collection.js:1058:12 @(shell):1:1
Esto nos dice que $range requires a numeric starting value, found value of type: null
.
Aparecería un mensaje similar si el valor final fuera nulo.
Aquí hay un documento con un null
valor final:
{ "_id" : 13, "start" : 1, "end" : null, "step" : 1 }
Apliquemos $range
:
db.range.aggregate(
[
{ $match: { _id: { $in: [ 13 ] } } },
{
$project:
{
_id: 0,
start: 1,
end: 1,
result: { $range: [ "$start", "$end", "$step" ] }
}
}
]
)
Resultado:
uncaught exception: Error: command failed: { "ok" : 0, "errmsg" : "$range requires a numeric ending value, found value of type: null", "code" : 34445, "codeName" : "Location34445" } : aggregate failed : [email protected]/mongo/shell/utils.js:25:13 [email protected]/mongo/shell/assert.js:18:14 [email protected]/mongo/shell/assert.js:639:17 [email protected]/mongo/shell/assert.js:729:16 [email protected]/mongo/shell/db.js:266:5 [email protected]/mongo/shell/collection.js:1058:12 @(shell):1:1
Esta vez nos dice que $range requires a numeric ending value, found value of type: null
.