Molte operazioni di aggiornamento in MongoDB hanno il potenziale per essere upsert. Un upsert è una combinazione di un inserto e un aggiornamento.
Funziona così:esegui un'operazione di aggiornamento in base a criteri di filtro e, se ci sono corrispondenze, vengono aggiornati solo i documenti corrispondenti, ma se non ci sono corrispondenze, viene inserito un nuovo documento.
Esempio
Supponiamo di avere una collezione chiamata pets
che contiene i seguenti documenti:
{ "_id" : 1, "name" : "Wag", "type" : "Dog" } { "_id" : 2, "name" : "Bark", "type" : "Dog" } { "_id" : 3, "name" : "Meow", "type" : "Cat" }
Potremmo eseguire la seguente operazione di aggiornamento che imposta il upsert
parametro su true
:
db.pets.updateOne(
{ name: "Wag" },
{ $set: { type: "Cow" } },
{ upsert: true }
)
Risultato:
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
In questo caso, c'era un documento corrispondente (ovvero c'è un documento con name: "Wag"
) e pertanto il documento di corrispondenza è stato aggiornato. Non è stato inserito nulla.
Possiamo verificarlo come segue:
db.pets.find()
Risultato:
{ "_id" : 1, "name" : "Wag", "type" : "Cow" } { "_id" : 2, "name" : "Bark", "type" : "Dog" } { "_id" : 3, "name" : "Meow", "type" : "Cat" }
Il primo documento ora ha un type
di Cow
.
Eseguiamo un'altra operazione di aggiornamento, sempre utilizzando upsert: true
. Ma questa volta, non ci sarà alcun documento corrispondente da aggiornare.
db.pets.updateOne(
{ name: "Bubbles" },
{ $set: { type: "Fish" } },
{ upsert: true }
)
Risultato:
{ "acknowledged" : true, "matchedCount" : 0, "modifiedCount" : 0, "upsertedId" : ObjectId("5fe1b4c8d9914101694100b7") }
In questo esempio, proviamo a trovare un documento che abbia name: "Bubbles"
ma non si trova nessuno.
Questa volta possiamo vedere che il matchedCount
è 0
e il modifiedCount
è anche 0
. Ciò significa che nessuno dei documenti esistenti è stato aggiornato.
Possiamo anche vedere che un upsertedId
è stato restituito, il che significa che un documento è stato capovolto.
Diamo un'altra occhiata alla raccolta di documenti:
db.pets.find()
Risultato:
{ "_id" : 1, "name" : "Wag", "type" : "Cow" } { "_id" : 2, "name" : "Bark", "type" : "Dog" } { "_id" : 3, "name" : "Meow", "type" : "Cat" } { "_id" : ObjectId("5fe1b4c8d9914101694100b7"), "name" : "Bubbles", "type" : "Fish" }
Possiamo vedere che un nuovo documento è stato inserito/smontato e ha lo stesso ID come indicato sopra.
L'upsert si è verificato perché questa volta non c'erano documenti corrispondenti da aggiornare (e quindi ne è stato inserito/upsert uno nuovo).
Se non avessimo impostato upsert: true
, quel documento non sarebbe stato inserito.
Aggiornamenti in blocco
Quando si esegue un aggiornamento in blocco, se si desidera specificare upsert: true
, devi usarlo con Bulk.find.upsert()
.
Può essere utilizzato con le seguenti operazioni di scrittura:
Bulk.find.replaceOne()
Bulk.find.updateOne()
Bulk.find.update()
La sintassi è questa:
Bulk.find(<query>).upsert().update(<update>);
Bulk.find(<query>).upsert().updateOne(<update>);
Bulk.find(<query>).upsert().replaceOne(<replacement>);
Esempio:
var bulk = db.pets.initializeUnorderedBulkOp();
bulk.find( { name: "Bruce" } ).upsert().replaceOne(
{
name: "Bruce",
type: "Bat",
}
);
bulk.execute();
Risultato:
BulkWriteResult({ "writeErrors" : [ ], "writeConcernErrors" : [ ], "nInserted" : 0, "nUpserted" : 1, "nMatched" : 0, "nModified" : 0, "nRemoved" : 0, "upserted" : [ { "index" : 0, "_id" : ObjectId("5fe1c179d9914101694100dd") } ] })
Possiamo vedere che un documento è stato alterato. Possiamo anche vedere il _id
che è stato generato per quel documento.
Ora, quando visualizziamo i documenti nella nostra raccolta, possiamo vedere il nuovo documento che è stato aggiornato:
db.pets.find()
Risultato:
{ "_id" : 1, "name" : "Wag", "type" : "Cow" } { "_id" : 2, "name" : "Bark", "type" : "Dog" } { "_id" : 3, "name" : "Meow", "type" : "Cat" } { "_id" : ObjectId("5fe1b4c8d9914101694100b7"), "name" : "Bubbles", "type" : "Fish" } { "_id" : ObjectId("5fe1c179d9914101694100dd"), "name" : "Bruce", "type" : "Bat" }