Muitas operações de atualização no MongoDB têm o potencial de serem upserts. Um upsert é uma combinação de uma inserção e uma atualização.
Funciona assim:Você executa uma operação de atualização com base em critérios de filtro, e se houver correspondências, apenas os documentos correspondentes serão atualizados, mas se não houver correspondências, um novo documento será inserido.
Exemplo
Suponha que tenhamos uma coleção chamada
pets
que contém os seguintes documentos:{ "_id" : 1, "name" : "Wag", "type" : "Dog" } { "_id" : 2, "name" : "Bark", "type" : "Dog" } { "_id" : 3, "name" : "Meow", "type" : "Cat" }
Poderíamos realizar a seguinte operação de atualização que define o
upsert
parâmetro para true
:db.pets.updateOne(
{ name: "Wag" },
{ $set: { type: "Cow" } },
{ upsert: true }
)
Resultado:
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
Nesse caso, havia um documento correspondente (ou seja, há um documento com
name: "Wag"
) e, portanto, o documento correspondente foi atualizado. Nada foi inserido. Podemos verificar isso da seguinte forma:
db.pets.find()
Resultado:
{ "_id" : 1, "name" : "Wag", "type" : "Cow" } { "_id" : 2, "name" : "Bark", "type" : "Dog" } { "_id" : 3, "name" : "Meow", "type" : "Cat" }
O primeiro documento agora tem um
type
de Cow
. Vamos executar outra operação de atualização, novamente usando
upsert: true
. Mas desta vez, não haverá nenhum documento correspondente para atualizar. db.pets.updateOne(
{ name: "Bubbles" },
{ $set: { type: "Fish" } },
{ upsert: true }
)
Resultado:
{ "acknowledged" : true, "matchedCount" : 0, "modifiedCount" : 0, "upsertedId" : ObjectId("5fe1b4c8d9914101694100b7") }
Neste exemplo, tentamos encontrar um documento que tenha
name: "Bubbles"
mas não há nenhum para ser encontrado. Desta vez, podemos ver que o
matchedCount
é 0
, e o modifiedCount
também é 0
. Isso significa que nenhum dos documentos existentes foi atualizado. Também podemos ver que um
upsertedId
foi retornado, o que significa que um documento foi upserted. Vamos dar outra olhada na coleção de documentos:
db.pets.find()
Resultado:
{ "_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" }
Podemos ver que um novo documento foi inserido/inserido e possui o mesmo ID indicado acima.
O upsert ocorreu porque desta vez não havia documentos correspondentes para atualizar (e, portanto, um novo foi inserido/upserted).
Se não tivéssemos definido
upsert: true
, esse documento não teria sido inserido. Upsert em atualizações em massa
Ao realizar uma atualização em massa, se você deseja especificar
upsert: true
, você precisa usá-lo com Bulk.find.upsert()
. Isso pode ser usado com as seguintes operações de gravação:
Bulk.find.replaceOne()
Bulk.find.updateOne()
Bulk.find.update()
A sintaxe fica assim:
Bulk.find(<query>).upsert().update(<update>);
Bulk.find(<query>).upsert().updateOne(<update>);
Bulk.find(<query>).upsert().replaceOne(<replacement>);
Exemplo:
var bulk = db.pets.initializeUnorderedBulkOp();
bulk.find( { name: "Bruce" } ).upsert().replaceOne(
{
name: "Bruce",
type: "Bat",
}
);
bulk.execute();
Resultado:
BulkWriteResult({ "writeErrors" : [ ], "writeConcernErrors" : [ ], "nInserted" : 0, "nUpserted" : 1, "nMatched" : 0, "nModified" : 0, "nRemoved" : 0, "upserted" : [ { "index" : 0, "_id" : ObjectId("5fe1c179d9914101694100dd") } ] })
Podemos ver que um documento foi upserted. Também podemos ver o
_id
que foi gerado para esse documento. Agora, quando visualizamos os documentos em nossa coleção, podemos ver o novo documento que foi atualizado:
db.pets.find()
Resultado:
{ "_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" }