W3docs

Atualização no MongoDB

Aprenda a atualizar documentos MongoDB em Python com update_one(), update_many(), upsert e operadores como $set, $inc e $push.

O PyMongo oferece dois métodos principais para modificar documentos em uma coleção: update_one() altera o primeiro documento que corresponde a um filtro, e update_many() altera todos os documentos correspondentes. Ambos os métodos utilizam os operadores de atualização do MongoDB — instruções como $set, $inc e $push — para descrever exatamente o que deve ser alterado, deixando o restante do documento intocado.

Este capítulo abrange:

  • Conexão ao MongoDB com PyMongo
  • update_one() — alterar um único documento
  • update_many() — alterar vários documentos de uma vez
  • Operadores de atualização: $set, $unset, $inc, $push, $pull
  • Atualização de campos aninhados com notação de ponto
  • Upserts — inserir ou atualizar em uma única etapa
  • Verificar o que foi modificado com o objeto de resultado

Se você ainda não inseriu nenhum documento, leia primeiro MongoDB Insert. Para a sintaxe de filtragem, consulte MongoDB Query.

Conectando ao MongoDB

Instale o driver, caso ainda não tenha feito isso:

pip install pymongo

Em seguida, conecte-se a um banco de dados e a uma coleção:

import pymongo

client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["mydatabase"]
mycol = db["mycollection"]

MongoClient é preguiçoso — ele não abre um socket de fato até a primeira operação. O banco de dados e a coleção são criados automaticamente na primeira vez que um documento é gravado neles.

Atualizando um Único Documento

update_one(filter, update) encontra o primeiro documento que corresponde a filter e aplica update a ele.

result = mycol.update_one(
    {"name": "Alice"},       # filter: which document to change
    {"$set": {"age": 31}}    # update: what to change
)

print(result.matched_count)   # 1 if a document was found
print(result.modified_count)  # 1 if a value actually changed

O operador $set sobrescreve os campos listados e mantém todos os outros campos do documento exatamente como estavam. Sem $set, o segundo argumento substituiria o documento inteiro, o que raramente é o que se deseja.

Por que matched_count e modified_count podem ser diferentes

Se o documento já tem age: 31, o MongoDB o encontra, mas não grava nada. Nesse caso, matched_count é 1 e modified_count é 0. Verifique sempre modified_count para confirmar que uma gravação real ocorreu.

Atualizando Vários Documentos

update_many(filter, update) aplica a mesma atualização a todos os documentos que correspondem ao filtro.

result = mycol.update_many(
    {"status": {"$ne": "closed"}},   # every document where status != "closed"
    {"$set": {"status": "open"}}
)

print(f"Matched:  {result.matched_count}")
print(f"Modified: {result.modified_count}")

update_many() é atômico por documento, mas não entre documentos. Cada documento individual é modificado atomicamente, mas outros clientes podem ler ou gravar entre as atualizações de documentos individuais dentro da mesma chamada update_many().

Operadores de Atualização

O MongoDB fornece um conjunto de operadores de atualização para que você possa expressar alterações com precisão sem precisar enviar o documento inteiro pela rede.

$set — definir valores de campo

# Set one field
mycol.update_one({"name": "Alice"}, {"$set": {"city": "Boston"}})

# Set multiple fields at once
mycol.update_one({"name": "Alice"}, {"$set": {"city": "Boston", "active": True}})

$unset — remover um campo

# Remove the "temporary" field from the matching document
mycol.update_one({"name": "Alice"}, {"$unset": {"temporary": ""}})

O valor que você atribui ao campo dentro de $unset é irrelevante — o MongoDB o ignora. A convenção é usar uma string vazia.

$inc — incrementar ou decrementar um número

# Add 5 to the "score" field (creates it at 5 if it does not exist)
mycol.update_one({"name": "Alice"}, {"$inc": {"score": 5}})

# Subtract 1
mycol.update_one({"name": "Alice"}, {"$inc": {"score": -1}})

$inc é seguro para contadores porque é uma operação atômica única — dois incrementos simultâneos serão aplicados corretamente.

$push — acrescentar a um array

# Add a tag to the "tags" array (creates the array if it does not exist)
mycol.update_one({"name": "Alice"}, {"$push": {"tags": "python"}})

$pull — remover elementos de um array

# Remove all occurrences of "python" from the "tags" array
mycol.update_one({"name": "Alice"}, {"$pull": {"tags": "python"}})

Atualizando Documentos Aninhados

Use a notação de ponto para acessar documentos incorporados sem reescrever o objeto aninhado inteiro.

Considere um documento com esta estrutura:

{
  "name": "Alice",
  "address": {
    "city": "New York",
    "state": "NY"
  }
}

Para alterar apenas o campo state dentro de address:

mycol.update_one(
    {"name": "Alice"},
    {"$set": {"address.state": "NJ"}}
)

O campo city dentro de address não é alterado. Você pode ir quantos níveis de profundidade forem necessários para o seu esquema — por exemplo, "address.geo.lat".

Upsert: Inserir ou Atualizar em Uma Única Etapa

Um upsert instrui o MongoDB: "atualize este documento se ele existir; insira-o se não existir." Passe upsert=True como argumento nomeado:

result = mycol.update_one(
    {"name": "Bob"},
    {"$set": {"age": 25, "status": "new"}},
    upsert=True
)

if result.upserted_id:
    print(f"Inserted new document with _id: {result.upserted_id}")
else:
    print("Updated an existing document")

Quando o MongoDB insere um novo documento via upsert, o atributo upserted_id do objeto de resultado contém o novo _id. Quando ele atualiza um documento existente, upserted_id é None.

update_many() também aceita upsert=True. Se nenhum documento corresponder, o MongoDB insere um novo documento — ele nunca insere vários documentos a partir de um único upsert.

Inspecionando o Objeto de Resultado

Tanto update_one() quanto update_many() retornam um objeto UpdateResult com três atributos úteis:

AtributoDescrição
matched_countNúmero de documentos que corresponderam ao filtro
modified_countNúmero de documentos que foram efetivamente alterados
upserted_id_id do documento recém-inserido (somente upsert); None caso contrário
result = mycol.update_many(
    {"role": "guest"},
    {"$set": {"role": "member"}}
)

print(f"Matched:  {result.matched_count}")
print(f"Modified: {result.modified_count}")
print(f"Upserted: {result.upserted_id}")

Erros Comuns

Esquecer um operador de atualização substitui o documento. Esta chamada apaga todos os campos exceto _id e substitui o documento por apenas age: 31:

# Dangerous — replaces the whole document
mycol.update_one({"name": "Alice"}, {"age": 31})

Sempre envolva suas alterações em um operador ($set, $inc, etc.).

Filtrar por _id requer um ObjectId. Os IDs de documento são armazenados como objetos ObjectId, não como strings simples:

from bson.objectid import ObjectId

mycol.update_one(
    {"_id": ObjectId("64a1f2c3d4e5f6a7b8c9d0e1")},
    {"$set": {"verified": True}}
)

Passar o ID como uma string simples não corresponderá a nada e não fará nada silenciosamente.

Próximos Passos

Was this page helpful?