db.collection.findOneAndUpdate()
MongoDB com drivers
Esta página documenta um método mongosh
. Para ver o método equivalente em um driver MongoDB, consulte a página correspondente da sua linguagem de programação:
Definição
db.collection.findOneAndUpdate( filter, update, options )
Atualiza um único documento com base nos critérios
filter
esort
.Dica
Novidades na versão 8.0: O método
updateOne()
inclui uma opçãosort
para atualizar o primeiro documento em uma ordem de classificação especificada pelo usuário.Retorna: Retorna o documento original por padrão. Retorna o documento atualizado se returnNewDocument estiver definido como true
ou returnDocument estiver definido comoafter
.
Compatibilidade
Você pode utilizar o db.collection.findOneAndUpdate()
para implantações hospedadas nos seguintes ambientes:
MongoDB Atlas: o serviço totalmente gerenciado para implantações do MongoDB na nuvem
MongoDB Enterprise: a versão autogerenciada e baseada em assinatura do MongoDB
MongoDB Community: uma versão com código disponível, de uso gratuito e autogerenciada do MongoDB
Sintaxe
O método findOneAndUpdate()
tem o seguinte formato:
db.collection.findOneAndUpdate( <filter>, <update document or aggregation pipeline>, { writeConcern: <document>, projection: <document>, sort: <document>, maxTimeMS: <number>, upsert: <boolean>, returnDocument: <string>, returnNewDocument: <boolean>, collation: <document>, arrayFilters: [ <filterdocument1>, ... ] } )
O método findOneAndUpdate()
utiliza os seguintes parâmetros:
Parâmetro | Tipo | Descrição | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
filter | documento | Os critérios de seleção para a atualização. Os mesmos seletores de consulta que no método Para atualizar o primeiro documento retornado na collection, especifique um documento vazio Se não for especificado, o padrão será um documento vazio. Se o campo de consulta não for um documento, a operação retornará um erro. Se nenhum documento corresponder ao | ||||||||||||||||||
update | documento ou array | O documento de atualização ou um pipeline de agregação.
| ||||||||||||||||||
writeConcern | documento | Opcional. Um documento que expressa o write concern. Omitir para usar o write concern padrão.
Não defina explicitamente a preocupação de gravação para a operação se for executada em uma transação. Para usar write concern com transações, consulte Transações e write concern. | ||||||||||||||||||
projection | documento | Opcional. Um subconjunto de campos para retornar. Para retornar todos os campos no documento retornado, omita este parâmetro. Se o argumento de projeção não for um documento, ocorrerá um erro na operação. | ||||||||||||||||||
sort | documento | Opcional. Especifica uma ordem de classificação para os documentos correspondidos pelo Se o argumento de classificação não for um documento, ocorrerá um erro com a operação. Consulte | ||||||||||||||||||
maxTimeMS | número | Opcional. Especifica um limite de tempo em milissegundos dentro do qual a operação deve ser concluída. Lança um erro se o limite for excedido. | ||||||||||||||||||
upsert | booleano | Opcional. Quando
Para evitar várias atualizações, certifique-se de que os campos O padrão é | ||||||||||||||||||
returnDocument | string | Opcional. A partir da versão 0.13.2 do
| ||||||||||||||||||
returnNewDocument | booleano | Opcional. Quando Padrão é | ||||||||||||||||||
collation | documento | Opcional. Especifica o agrupamento a ser usado para a operação. A colocação permite que os usuários especifiquem regras específicas do idioma para comparação de strings, como regras para letras maiúsculas e marcas de acento. A opção de agrupamento tem a seguinte sintaxe:
Ao especificar agrupamento, o campo Se o agrupamento não for especificado, mas a coleção tiver um agrupamento padrão (consulte Se nenhum agrupamento for especificado para a coleção ou para as operações, o MongoDB usa a comparação binária simples usada nas versões anteriores para comparações de strings. Você não pode especificar vários agrupamentos para uma operação. Por exemplo, você não pode especificar agrupamentos diferentes por campo ou, se estiver realizando uma busca com uma classificação, não poderá usar um agrupamento para a busca e outro para a classificação. | ||||||||||||||||||
arrayFilters | array | Opcional. Uma array de documentos de filtro que determina quais elementos da array modificar para uma operação de atualização em um campo da array. No documento de atualização, use o operador posicional filtrado O Você pode incluir o mesmo identificador várias vezes no documento de atualização; entretanto, para cada identificador distinto (
No entanto, você pode especificar condições compostas no mesmo identificador em um único documento de filtro, como nos exemplos a seguir:
Para ver exemplos, consulte a página Operações de atualização de array com
|
Comportamento
Desempenho
As gravações com nova tentativa exigem que o método findOneAndUpdate()
copie o documento inteiro em uma coleção lateral especial para cada nó em um conjunto de réplicas antes de executar a atualização. Isso pode tornar findOneAndUpdate()
uma operação cara ao lidar com documentos grandes ou grandes conjuntos de réplicas.
Novidades na versão 8.0: Para atualizar o primeiro documento em uma ordem definida pelo usuário com melhor desempenho, use o método db.collection.updateOne()
com a opção sort
.
Correspondência de documento
db.collection.findOneAndUpdate()
atualiza o primeiro documento correspondente na coleção que corresponde ao filter
. Se nenhum documento corresponder ao filter
, nenhum documento será atualizado.
O parâmetro sort
pode ser usado para influenciar qual documento é atualizado.
Projeção
Importante
Consistência de linguagem
Como parte da criação da projeção find()
e findAndModify()
consistente com o estágio $project
da agregação,
A projeção
find()
efindAndModify()
pode aceitar expressões de agregação e sintaxe.O MongoDB impõe restrições adicionais em relação às projeções. Consulte Restrições de Projeção para detalhes.
O parâmetro projection
obtém um documento no seguinte formato:
{ field1 : <value>, field2 : <value> ... }
Projeção | Descrição |
---|---|
<field>: <1 or true> | Especifica a inclusão de um campo. Se você especificar um número inteiro diferente de zero para o valor de projeção, a operação tratará o valor como true . |
<field>: <0 or false> | Especifica a exclusão de um campo. |
"<field>.$": <1 or true> | Usa o operador de projeção de array Não disponível para visualizações. |
<field>: <array projection> | Usa os operadores de projeção de array ( Não disponível para visualizações. |
<field>: <aggregation expression> | Especifica o valor do campo projetado. Com o uso de expressões de agregação e sintaxe, incluindo o uso de literais e variáveis de agregação, você pode projetar novos campos ou projetar campos existentes com novos valores.
|
Especificação de campo incorporada
Para campos em documentos incorporados, você pode especificar o campo usando:
notação de pontos, por exemplo
"field.nestedfield": <value>
formato aninhado, por exemplo
{ field: { nestedfield: <value> } }
_id
Projeção de campo
O campo _id
é incluído nos documentos retornados por padrão, a menos que você especifique explicitamente _id: 0
na projeção para suprimir o campo.
Inclusão ou exclusão
Uma projection
não pode conter especificações de inclusão e exclusão, com exceção do campo _id
:
Em projeções que incluem explicitamente campos, o campo
_id
é o único campo que você pode excluir explicitamente.Em projeções que excluem explicitamente campos, o campo
_id
é o único campo que você pode incluir explicitamente; entretanto, o campo_id
é incluído por padrão.
Para obter mais informações sobre "projection", consulte também:
Coleções fragmentadas
Para usar db.collection.findOneAndUpdate()
em uma coleção fragmentada, o filtro de query deve incluir uma condição de igualdade na chave de fragmento.
Os documentos em uma coleção fragmentada podem não ter campos de chave de fragmento. Para direcionar um documento que não tem a chave de fragmento, você pode usar a correspondência de igualdade null
em conjunto com outra condição de filtro (como no campo _id
). Por exemplo:
{ _id: <value>, <shardkeyfield>: null } // _id of the document missing shard key
Modificação da chave de fragmento
Você pode atualizar o valor da chave de fragmento de um documento, a menos que o campo de chave de fragmento seja o campo de _id
imutável.
Aviso
Os documentos em coleções fragmentadas podem não ter os campos chave de fragmentado. Tome cuidado para evitar remover acidentalmente a chave de fragmento ao alterar o valor dela em um documento.
Para modificar o valor da chave de fragmento existente com db.collection.findOneAndUpdate()
:
Você deve executar em um
mongos
. Não emita a operação diretamente no fragmento.Você deve executar em uma transação ou como uma gravação repetível.
Você deve incluir um filtro de igualdade na chave de shard completa.
Chave de fragmento ausente
Documentos em uma coleção fragmentada podem estar sem os campos de chave de fragmento. Para usar db.collection.findOneAndUpdate()
para definir a chave de fragmento ausente do documento,
Você deve executar em um
mongos
. Não emita a operação diretamente no fragmento.Você deve executar em uma transação ou como retryable write se o novo valor da chave de shard não for
null
.Você deve incluir um filtro de igualdade na chave de shard completa.
Dica
Como um valor de chave ausente é retornado como parte de uma correspondência de igualdade nula,
para evitar a atualização de uma chave de valor nulo, inclua
condições de consulta (como no campo _id
) conforme apropriado.
Veja também:
Transações
db.collection.findOneAndUpdate()
pode ser usado dentro de transações distribuídas.
Importante
Na maioria dos casos, uma transação distribuída incorre em um custo de desempenho maior do que as gravações de um único documento, e a disponibilidade de transações distribuídas não deve substituir o design eficaz do esquema. Em muitos cenários, o modelo de dados desnormalizado (documentos e arrays incorporados) continuará a ser ideal para seus dados e casos de uso. Ou seja, para muitos cenários, modelar seus dados adequadamente minimizará a necessidade de transações distribuídas.
Para considerações adicionais sobre o uso de transações (como limite de tempo de execução e limite de tamanho do oplog), consulte também Considerações de produção.
Inserção nas Transações
Você pode criar coleção e índices dentro de uma transação distribuída se a transação não for uma transação de gravação cross-fragmento.
db.collection.findOneAndUpdate()
com upsert: true
pode ser executado em uma coleção existente ou em uma coleção inexistente. Se for executada em uma coleção inexistente, a operação cria a coleção.
Write concerns e transações
Não defina explicitamente a preocupação de gravação para a operação se for executada em uma transação. Para usar write concern com transações, consulte Transações e write concern.
Entradas de oplog
Se uma operação db.collection.findOneAndUpdate()
conseguir atualizar um documento, ela adicionará uma entrada no oplog (log de operações). Se a operação falhar ou não encontrar um documento para atualizar, ela não adicionará uma entrada no oplog.
Exemplos
Atualizar um documento
A collection grades
contém documentos semelhantes aos seguintes:
{ _id: 6305, name : "A. MacDyver", "assignment" : 5, "points" : 24 }, { _id: 6308, name : "B. Batlock", "assignment" : 3, "points" : 22 }, { _id: 6312, name : "M. Tagnum", "assignment" : 5, "points" : 30 }, { _id: 6319, name : "R. Stiles", "assignment" : 2, "points" : 12 }, { _id: 6322, name : "A. MacDyver", "assignment" : 2, "points" : 14 }, { _id: 6234, name : "R. Stiles", "assignment" : 1, "points" : 10 }
A operação a seguir encontra o primeiro documento onde name : R. Stiles
e aumenta a pontuação em 5
:
db.grades.findOneAndUpdate( { "name" : "R. Stiles" }, { $inc: { "points" : 5 } } )
A operação retorna o documento original antes da atualização:
{ _id: 6319, name: "R. Stiles", "assignment" : 2, "points" : 12 }
Se returnNewDocument
fosse verdadeiro, a operação retornaria o documento atualizado.
Classificar e atualizar um documento
A collection grades
contém documentos semelhantes aos seguintes:
{ _id: 6305, name : "A. MacDyver", "assignment" : 5, "points" : 24 }, { _id: 6308, name : "B. Batlock", "assignment" : 3, "points" : 22 }, { _id: 6312, name : "M. Tagnum", "assignment" : 5, "points" : 30 }, { _id: 6319, name : "R. Stiles", "assignment" : 2, "points" : 12 }, { _id: 6322, name : "A. MacDyver", "assignment" : 2, "points" : 14 }, { _id: 6234, name : "R. Stiles", "assignment" : 1, "points" : 10 }
A operação seguinte atualiza um documento onde name : "A. MacDyver"
. A operação classifica os documentos correspondentes por points
crescente para atualizar o documento correspondente com o mínimo de pontos.
db.grades.findOneAndUpdate( { "name" : "A. MacDyver" }, { $inc : { "points" : 5 } }, { sort : { "points" : 1 } } )
A operação retorna o documento original antes da atualização:
{ _id: 6322, name: "A. MacDyver", "assignment" : 2, "points" : 14 }
Projetar o documento retornado
A seguinte operação usa projeção para retornar somente os campos _id
, points
e assignment
no documento retornado:
db.grades.findOneAndUpdate( { "name" : "A. MacDyver" }, { $inc : { "points" : 5 } }, { sort : { "points" : 1 }, projection: { "assignment" : 1, "points" : 1 } } )
A operação retorna o documento original somente com os campos especificados no documento projection
e o campo _id
como ele não foi explicitamente suprimido (_id: 0
) no documento de projeção.
{ "_id" : 6322, "assignment" : 2, "points" : 14 }
Atualizar documento com limite de tempo
A seguinte operação define um limite de tempo de 5ms para concluir a atualização:
try { db.grades.findOneAndUpdate( { "name" : "A. MacDyver" }, { $inc : { "points" : 5 } }, { sort: { "points" : 1 }, maxTimeMS : 5 }; ); } catch(e){ print(e); }
Se a operação exceder o limite de tempo, ela retornará:
Error: findAndModifyFailed failed: { "ok" : 0, "errmsg" : "operation exceeded time limit", "code" : 50 }
Atualizar documento com upsert
A seguinte operação utiliza o campo upsert
para inserir o documento de atualização se nenhum corresponder ao filter
:
try { db.grades.findOneAndUpdate( { "name" : "A.B. Abracus" }, { $set: { "name" : "A.B. Abracus", "assignment" : 5}, $inc : { "points" : 5 } }, { sort: { "points" : 1 }, upsert:true, returnNewDocument : true } ); } catch (e){ print(e); }
A operação retorna o seguinte:
{ "_id" : ObjectId("5789249f1c49e39a8adc479a"), "name" : "A.B. Abracus", "assignment" : 5, "points" : 5 }
Se returnNewDocument
fosse falso, a operação retornará null
, pois não há nenhum documento original para retornar.
Especifique o agrupamento
A colocação permite que os usuários especifiquem regras específicas do idioma para comparação de strings, como regras para letras maiúsculas e marcas de acento.
Uma coleção myColl
possui os seguintes documentos:
{ _id: 1, category: "café", status: "A" } { _id: 2, category: "cafe", status: "a" } { _id: 3, category: "cafE", status: "a" }
A seguinte operação inclui a opção coleção:
db.myColl.findOneAndUpdate( { category: "cafe" }, { $set: { status: "Updated" } }, { collation: { locale: "fr", strength: 1 } } );
A operação retorna o seguinte documento:
{ "_id" : 1, "category" : "café", "status" : "A" }
Operações de atualização de array com arrayFilters
Observação
arrayFilters
não está disponível para atualizações que usam um pipeline de agregação
Ao atualizar um campo de array, você pode especificar arrayFilters
que determinam quais elementos de array atualizar.
arrayFilters
Atualizar elementos que correspondem aos critérios
Observação
arrayFilters
não está disponível para atualizações que usam um pipeline de agregação
Crie uma collection students
com os seguintes documentos:
db.students.insertMany( [ { "_id" : 1, "grades" : [ 95, 92, 90 ] }, { "_id" : 2, "grades" : [ 98, 100, 102 ] }, { "_id" : 3, "grades" : [ 95, 110, 100 ] } ] )
Para modificar todos os elementos maiores ou iguais a 100
na array grades
, use o operador posicional filtrado $[<identifier>]
com a opção arrayFilters
no método db.collection.findOneAndUpdate()
:
db.students.findOneAndUpdate( { grades: { $gte: 100 } }, { $set: { "grades.$[element]" : 100 } }, { arrayFilters: [ { "element": { $gte: 100 } } ] } )
A operação atualiza o campo grades
para um único documento e, após a operação, a collection tem os seguintes documentos:
{ "_id" : 1, "grades" : [ 95, 92, 90 ] } { "_id" : 2, "grades" : [ 98, 100, 100 ] } { "_id" : 3, "grades" : [ 95, 110, 100 ] }
Atualizar elementos específicos de uma array de documentos
Observação
arrayFilters
não está disponível para atualizações que usam um pipeline de agregação
Crie uma collection students2
com os seguintes documentos:
db.students2.insertMany( [ { "_id" : 1, "grades" : [ { "grade" : 80, "mean" : 75, "std" : 6 }, { "grade" : 85, "mean" : 90, "std" : 4 }, { "grade" : 85, "mean" : 85, "std" : 6 } ] }, { "_id" : 2, "grades" : [ { "grade" : 90, "mean" : 75, "std" : 6 }, { "grade" : 87, "mean" : 90, "std" : 3 }, { "grade" : 85, "mean" : 85, "std" : 4 } ] } ] )
A operação a seguir localiza um documento em que o campo _id
é igual a 1
e usa o operador posicional filtrado $[<identifier>]
com arrayFilters
para modificar o mean
para todos os elementos na array grades
em que a nota é maior ou igual a 85
.
db.students2.findOneAndUpdate( { _id : 1 }, { $set: { "grades.$[elem].mean" : 100 } }, { arrayFilters: [ { "elem.grade": { $gte: 85 } } ] } )
A operação atualiza o campo grades
para um único documento e, após a operação, a collection tem os seguintes documentos:
{ "_id" : 1, "grades" : [ { "grade" : 80, "mean" : 75, "std" : 6 }, { "grade" : 85, "mean" : 100, "std" : 4 }, { "grade" : 85, "mean" : 100, "std" : 6 } ] } { "_id" : 2, "grades" : [ { "grade" : 90, "mean" : 75, "std" : 6 }, { "grade" : 87, "mean" : 90, "std" : 3 }, { "grade" : 85, "mean" : 85, "std" : 4 } ] }
Usar um aggregation pipeline para atualizações
db.collection.findOneAndUpdate()
pode aceitar um pipeline de agregação para a atualização. O pipeline pode consistir nas seguintes etapas:
$addFields
e seu alias$set
$replaceRoot
e seu nome alternativo$replaceWith
.
O uso do aggregation pipeline permite uma instrução de atualização mais expressiva, como atualizações condicionais Express com base em valores de campo atuais ou atualização de um campo usando o valor de outro(s) campo(s).
Por exemplo, criar uma collection students2
com os seguintes documentos:
db.students2.insertMany( [ { "_id" : 1, "grades" : [ { "grade" : 80, "mean" : 75, "std" : 6 }, { "grade" : 85, "mean" : 90, "std" : 4 }, { "grade" : 85, "mean" : 85, "std" : 6 } ] }, { "_id" : 2, "grades" : [ { "grade" : 90, "mean" : 75, "std" : 6 }, { "grade" : 87, "mean" : 90, "std" : 3 }, { "grade" : 85, "mean" : 85, "std" : 4 } ] } ] )
A operação a seguir localiza um documento em que o campo _id
é igual a 1
e usa um aggregation pipeline para calcular um novo total
de campo a partir do campo grades
:
db.students2.findOneAndUpdate( { _id : 1 }, [ { $set: { "total" : { $sum: "$grades.grade" } } } ], // The $set stage is an alias for ``$addFields`` stage { returnNewDocument: true } )
Observação
A operação retorna o documento atualizado:
{ "_id" : 1, "grades" : [ { "grade" : 80, "mean" : 75, "std" : 6 }, { "grade" : 85, "mean" : 90, "std" : 4 }, { "grade" : 85, "mean" :85, "std" : 6 } ], "total" : 250 }