MongoDB tiene un $push operador y un $addToSet operador, los cuales hacen algo muy similar.
Ambos operadores agregan valores a una matriz existente. La principal diferencia está en la forma en que manejan las matrices que ya contienen el valor que está tratando de agregar, y también en los modificadores que se pueden usar.
Las diferencias
| Valores existentes | Si el valor ya existe en la matriz, $push aún agregará el valor (lo que resultará en valores duplicados). Sin embargo, $addToSet solo agrega el valor si aún no existe en la matriz. Por lo tanto, si el valor ya existe, $addToSet no lo agregará (no hará nada). |
| Modificadores | El $push El operador se puede usar con modificadores adicionales, como $sort , $slice y $position , mientras que $addToSet no puede (al menos, no a partir de MongoDB 4.4). |
Valores existentes
Supongamos que tenemos una colección con los siguientes documentos:
db.players.find() Resultado:
{ "_id" : 1, "scores" : [ 1, 5, 3 ] }
{ "_id" : 2, "scores" : [ 8, 17, 18 ] }
{ "_id" : 3, "scores" : [ 3, 5, 5 ] }
Usemos $addToSet para intentar agregar un valor a una de las matrices.
db.players.update(
{ _id: 3 },
{ $addToSet: { scores: 5 } }
) Salida:
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
Esto nos dice que hubo un documento coincidente (documento 3), pero no fue modificado. No se modificó porque el valor que intentamos insertar (5 ) ya existe en la matriz.
Miremos en la colección:
db.players.find() Resultado:
{ "_id" : 1, "scores" : [ 1, 5, 3 ] }
{ "_id" : 2, "scores" : [ 8, 17, 18 ] }
{ "_id" : 3, "scores" : [ 3, 5, 5 ] } Como era de esperar, el documento 3 no se ha modificado.
Intentemos $push en cambio:
db.players.update(
{ _id: 3 },
{ $push: { scores: 5 } }
) Salida:
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) Esta vez vemos que el documento fue modificado.
Podemos verificar esto revisando la colección nuevamente:
db.products.find() Resultado:
{ "_id" : 1, "scores" : [ 1, 5, 3 ] }
{ "_id" : 2, "scores" : [ 8, 17, 18 ] }
{ "_id" : 3, "scores" : [ 3, 5, 5, 5 ] } Modificadores
El $push El operador se puede usar con modificadores como $position , $sort y $slice .
El $addToSet El operador no se puede usar con estos modificadores.
Esto es lo que sucede si trato de usar estos modificadores con $addToSet :
db.players.update(
{ _id: 3 },
{
$addToSet: {
scores: {
$each: [ 12 ],
$position: 0,
$sort: 1,
$slice: 5
}
}
}
) Salida:
WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 2,
"errmsg" : "Found unexpected fields after $each in $addToSet: { $each: [ 12.0 ], $position: 0.0, $sort: 1.0, $slice: 5.0 }"
}
})
El mensaje de error nos dice que $position , $sort y $slice son campos inesperados (es decir, no deberían estar ahí).
Probemos los mismos modificadores con $push :
db.players.update(
{ _id: 3 },
{
$push: {
scores: {
$each: [ 12 ],
$position: 0,
$sort: 1,
$slice: 5
}
}
}
) Salida:
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) Esta vez funcionó sin errores.
Verifique el resultado:
db.players.find() Resultado:
{ "_id" : 1, "scores" : [ 1, 5, 3 ] }
{ "_id" : 2, "scores" : [ 8, 17, 18 ] }
{ "_id" : 3, "scores" : [ 3, 5, 5, 5, 12 ] }
Podemos ver que el valor ha sido añadido. Aunque especificamos $position: 0 , también especificamos $sort: 1 , lo que significa que la matriz se ordenó después de que la posicionáramos.
También especificamos $slice: 5 , que limitaba la matriz a solo 5 elementos (que resultó ser exactamente cuántos elementos había en la matriz de todos modos).