sql >> Base de Datos >  >> NoSQL >> MongoDB

MongoDB $push vs $addToSet:¿Cuál es la diferencia?

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).