MongoDB ha un $push
operatore e un $addToSet
operatore, entrambi i quali fanno una cosa molto simile.
Entrambi gli operatori aggiungono valori a una matrice esistente. La differenza principale è nel modo in cui gestiscono gli array che contengono già il valore che stai cercando di aggiungere e anche nei modificatori che possono essere utilizzati.
Le differenze
Valori esistenti | Se il valore esiste già nell'array, $push aggiungerà comunque il valore (con conseguente duplicazione dei valori). Tuttavia, $addToSet aggiunge il valore solo se non esiste già nell'array. Pertanto, se il valore esiste già, $addToSet non lo aggiungerà (non farà nulla). |
Modificatori | Il $push può essere utilizzato con modificatori aggiuntivi, come $sort , $slice e $position , mentre $addToSet non può (almeno, non a partire da MongoDB 4.4). |
Valori esistenti
Supponiamo di avere una collezione con i seguenti documenti:
db.players.find()
Risultato:
{ "_id" : 1, "scores" : [ 1, 5, 3 ] } { "_id" : 2, "scores" : [ 8, 17, 18 ] } { "_id" : 3, "scores" : [ 3, 5, 5 ] }
Usiamo $addToSet
per provare ad aggiungere un valore a uno degli array.
db.players.update(
{ _id: 3 },
{ $addToSet: { scores: 5 } }
)
Uscita:
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
Questo ci dice che c'era un documento corrispondente (documento 3), ma non è stato modificato. Non è stato modificato perché il valore che abbiamo provato a inserire (5
) esiste già nell'array.
Diamo un'occhiata alla collezione:
db.players.find()
Risultato:
{ "_id" : 1, "scores" : [ 1, 5, 3 ] } { "_id" : 2, "scores" : [ 8, 17, 18 ] } { "_id" : 3, "scores" : [ 3, 5, 5 ] }
Come previsto, il documento 3 non è stato modificato.
Proviamo $push
invece:
db.players.update(
{ _id: 3 },
{ $push: { scores: 5 } }
)
Uscita:
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
Questa volta vediamo che il documento è stato modificato.
Possiamo verificarlo controllando di nuovo la collezione:
db.products.find()
Risultato:
{ "_id" : 1, "scores" : [ 1, 5, 3 ] } { "_id" : 2, "scores" : [ 8, 17, 18 ] } { "_id" : 3, "scores" : [ 3, 5, 5, 5 ] }
Modificatori
Il $push
può essere utilizzato con modificatori come $position
, $sort
e $slice
.
Il $addToSet
l'operatore non può essere utilizzato con questi modificatori.
Ecco cosa succede se provo a utilizzare questi modificatori con $addToSet
:
db.players.update(
{ _id: 3 },
{
$addToSet: {
scores: {
$each: [ 12 ],
$position: 0,
$sort: 1,
$slice: 5
}
}
}
)
Uscita:
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 }" } })
Il messaggio di errore ci dice che il $position
, $sort
e $slice
sono campi imprevisti (cioè non dovrebbero essere presenti).
Proviamo gli stessi modificatori con $push
:
db.players.update(
{ _id: 3 },
{
$push: {
scores: {
$each: [ 12 ],
$position: 0,
$sort: 1,
$slice: 5
}
}
}
)
Uscita:
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
Questa volta ha funzionato senza errori.
Verifica il risultato:
db.players.find()
Risultato:
{ "_id" : 1, "scores" : [ 1, 5, 3 ] } { "_id" : 2, "scores" : [ 8, 17, 18 ] } { "_id" : 3, "scores" : [ 3, 5, 5, 5, 12 ] }
Possiamo vedere che il valore è stato aggiunto. Anche se abbiamo specificato $position: 0
, abbiamo anche specificato $sort: 1
, il che significa che l'array è stato ordinato dopo averlo posizionato.
Abbiamo anche specificato $slice: 5
, che limitava l'array a soli 5 elementi (che, come si è scoperto, erano comunque esattamente quanti elementi c'erano nell'array).