No MongoDB o
db.collection.findAndModify()
O método modifica e retorna um único documento. A
collection
parte é o nome da coleção com a qual executar a operação. 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" }
Podemos usar o
db.collection.findAndModify()
método para modificar um desses documentos. db.pets.findAndModify({
query: { type: "Dog" },
update: { type: "Cow" }
})
Resultado:
{ "_id" : 1, "name" : "Wag", "type" : "Dog" }
Por padrão, ele retorna o documento original (não a versão modificada).
Observe que apenas um cão foi atualizado, embora existam dois cães na coleção.
Vamos conferir a coleção.
db.pets.find()
Resultado:
{ "_id" : 1, "type" : "Cow" } { "_id" : 2, "name" : "Bark", "type" : "Dog" } { "_id" : 3, "name" : "Meow", "type" : "Cat" }
Podemos ver que o primeiro documento agora contém uma vaca em vez de um cachorro. No entanto, também podemos ver que o campo de nome do documento desapareceu.
Isso porque, quando você passa um documento para o
update
argumento, db.collection.findAndModify()
realiza uma substituição. Usando um operador de atualização
Se quiséssemos atualizar um campo, mas deixar o resto do documento intacto, precisaríamos incluir a(s) expressão(ões) do operador de atualização relevante(s) em nosso documento.
Com a coleção em seu estado atual, vamos executar outro
findAndModify()
operação contra ele, mas desta vez usaremos o $set
update para definir apenas o campo que queremos alterar. db.pets.findAndModify({
query: { type: "Dog" },
update: { $set: { type: "Horse" } }
})
Resultado:
{ "_id" : 2, "name" : "Bark", "type" : "Dog" }
Desta vez, o cão restante foi atualizado.
Vamos dar uma olhada na coleção.
db.pets.find()
Resultado:
{ "_id" : 1, "type" : "Cow" } { "_id" : 2, "name" : "Bark", "type" : "Horse" } { "_id" : 3, "name" : "Meow", "type" : "Cat" }
Desta vez, o campo relevante foi atualizado e o restante do documento permaneceu intacto.
Devolva o documento modificado
Por padrão, o documento original é retornado quando você usa
db.collection.findAndModify()
. Se preferir que o documento modificado seja devolvido, use o
new
parâmetro. Por padrão, isso é
new: false
, o que resulta na devolução do documento original. Mas especificando new: true
resulta no retorno do documento modificado. Vamos fazer outra modificação, mas desta vez usaremos
new: true
. db.pets.findAndModify({
query: { name: "Meow" },
update: { $set: { name: "Scratch" } },
new: true
})
Resultado:
{ "_id" : 3, "name" : "Scratch", "type" : "Cat" }
Então, renomeamos
Meow
para Scratch
e a saída reflete nossas mudanças. Upserts
Você pode realizar upserts especificando
upsert: true
. Um upsert é uma opção que você pode usar em operações de atualização. Se o documento especificado não existir, um novo será inserido. Se sim existir, o documento original será atualizado (e nenhum documento será inserido).
Exemplo usando upsert: false
Aqui está um exemplo de tentativa de atualizar um documento inexistente quando
upsert: false
. db.pets.findAndModify({
query: { _id: 4 },
update: { _id: 4, name: "Fetch", type: "Dog" },
new: true
})
Resultado:
null
O documento não existia na coleção e então
findAndModify()
retornou null
. Embora não tenhamos especificado upsert: false
, sabemos que era falso porque esse é o valor padrão (ou seja, esse é o valor usado quando você não especifica uma opção de upsert). Se dermos outra olhada na coleção, podemos ver que o documento não foi upserted.
db.pets.find()
Resultado:
{ "_id" : 1, "type" : "Cow" } { "_id" : 2, "name" : "Bark", "type" : "Horse" } { "_id" : 3, "name" : "Scratch", "type" : "Cat" }
Exemplo usando upsert: true
Agora aqui está novamente, mas desta vez especificamos
upsert: true
. db.pets.findAndModify({
query: { _id: 4 },
update: { _id: 4, name: "Fetch", type: "Dog" },
new: true,
upsert: true
})
Resultado:
{ "_id" : 4, "name" : "Fetch", "type" : "Dog" }
Desta vez, um novo documento é upserted e vemos o documento upserted como a saída (porque especificamos
new: true
). Vamos verificar a coleção novamente.
db.pets.find()
Resultado:
{ "_id" : 1, "type" : "Cow" } { "_id" : 2, "name" : "Bark", "type" : "Horse" } { "_id" : 3, "name" : "Scratch", "type" : "Cat" } { "_id" : 4, "name" : "Fetch", "type" : "Dog" }
Assim, podemos ver que o novo documento foi de fato alterado.
O parâmetro arrayFilters
Ao trabalhar com arrays, você pode usar os
arrayFilters
parâmetro junto com o posicional $
operador para determinar quais elementos da matriz devem ser atualizados. Isso permite que você atualize um elemento da matriz com base em seu valor, mesmo que você não saiba sua posição. Por exemplo, suponha que temos uma coleção chamada
players
com os seguintes documentos:{ "_id" : 1, "scores" : [ 1, 5, 3 ] } { "_id" : 2, "scores" : [ 8, 17, 18 ] } { "_id" : 3, "scores" : [ 15, 11, 8 ] }
Poderíamos executar a seguinte consulta para atualizar apenas os elementos do array que possuem um valor maior que um determinado valor (neste caso 10).
db.players.findAndModify({
query: { scores: { $gte: 10 } },
update: { $set: { "scores.$[e]" : 10 } },
arrayFilters: [ { "e": { $gte: 10 } } ]
})
Resultado:
{ "_id" : 2, "scores" : [ 8, 17, 18 ] }
Como esperado, isso atualiza apenas um documento, mesmo que dois documentos correspondam aos critérios.
Veja como estão os documentos agora.
db.players.find()
Resultado:
{ "_id" : 1, "scores" : [ 1, 5, 3 ] } { "_id" : 2, "scores" : [ 8, 10, 10 ] } { "_id" : 3, "scores" : [ 15, 11, 8 ] }
O Documento 2 teve dois elementos do array atualizados, porque esses elementos correspondiam aos critérios.
Mais informações
O
db.collection.findAndModify()
também aceita outros parâmetros, como writeConcern
, collection
, bypassDocumentValidation
e mais. Consulte a documentação do MongoDB para
db.collections.findAndModify()
Para maiores informações.