W3docs

Actualización en MongoDB

Aprende a actualizar documentos MongoDB en Python con update_one(), update_many(), upsert y operadores como $set, $inc y $push.

PyMongo proporciona dos métodos principales para modificar documentos en una colección: update_one() cambia el primer documento que coincide con un filtro, y update_many() cambia todos los documentos que coincidan. Ambos métodos utilizan los operadores de actualización de MongoDB — instrucciones como $set, $inc y $push — para describir exactamente qué debe cambiar, dejando el resto del documento intacto.

Este capítulo cubre:

  • Conexión a MongoDB con PyMongo
  • update_one() — cambiar un solo documento
  • update_many() — cambiar muchos documentos a la vez
  • Operadores de actualización: $set, $unset, $inc, $push, $pull
  • Actualización de campos anidados con notación de puntos
  • Upserts — insertar o actualizar en un solo paso
  • Verificar qué se modificó con el objeto de resultado

Si aún no has insertado ningún documento, lee primero MongoDB Insert. Para la sintaxis de filtros, consulta MongoDB Query.

Conexión a MongoDB

Instala el driver si aún no lo has hecho:

pip install pymongo

Luego conéctate a una base de datos y una colección:

import pymongo

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

MongoClient es perezoso — no abre realmente un socket hasta la primera operación. La base de datos y la colección se crean automáticamente la primera vez que se escribe un documento en ellas.

Actualizar un Solo Documento

update_one(filter, update) encuentra el primer documento que coincide con filter y le aplica update.

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

El operador $set sobreescribe los campos indicados y deja todos los demás campos del documento exactamente como estaban. Sin $set, el segundo argumento reemplazaría el documento completo, lo cual rara vez es lo que se desea.

Por qué matched_count y modified_count pueden diferir

Si el documento ya tiene age: 31, MongoDB lo encuentra pero no escribe nada. En ese caso, matched_count es 1 y modified_count es 0. Comprueba siempre modified_count para confirmar que ocurrió una escritura real.

Actualizar Múltiples Documentos

update_many(filter, update) aplica la misma actualización a todos los documentos que coincidan con el 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() es atómico por documento, pero no entre documentos. Cada documento individual se modifica de forma atómica, pero otros clientes pueden leer o escribir entre las actualizaciones individuales dentro de la misma llamada a update_many().

Operadores de Actualización

MongoDB proporciona un conjunto de operadores de actualización para que puedas expresar los cambios con precisión sin enviar el documento completo por la red.

$set — establecer 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 — eliminar un campo

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

El valor que asignas al campo dentro de $unset es irrelevante — MongoDB lo ignora. La convención es usar una cadena vacía.

$inc — incrementar o decrementar un 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 es seguro para contadores porque es una operación atómica única — dos incrementos simultáneos se aplicarán correctamente.

$push — agregar a un 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 — eliminar elementos de un array

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

Actualización de Documentos Anidados

Usa la notación de puntos para acceder a documentos embebidos sin reescribir el objeto anidado completo.

Considera un documento con esta forma:

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

Para cambiar solo el campo state dentro de address:

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

El campo city dentro de address no se toca. Puedes ir tan profundo como requiera tu esquema — por ejemplo "address.geo.lat".

Upsert: Insertar o Actualizar en Un Solo Paso

Un upsert le indica a MongoDB: "actualiza este documento si existe; insértalo si no existe". Pasa upsert=True como argumento de palabra clave:

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")

Cuando MongoDB inserta un nuevo documento mediante upsert, el atributo upserted_id del objeto resultado contiene el nuevo _id. Cuando actualiza un documento existente, upserted_id es None.

update_many() también acepta upsert=True. Si ningún documento coincide, MongoDB inserta un nuevo documento — nunca inserta múltiples documentos desde un único upsert.

Inspección del Objeto de Resultado

Tanto update_one() como update_many() devuelven un objeto UpdateResult con tres atributos útiles:

AtributoDescripción
matched_countNúmero de documentos que coincidieron con el filtro
modified_countNúmero de documentos que fueron realmente modificados
upserted_id_id del documento recién insertado (solo upsert); None en caso contrario
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}")

Errores Comunes

Olvidar un operador de actualización reemplaza el documento. Esta llamada elimina todos los campos excepto _id y reemplaza el documento solo con age: 31:

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

Envuelve siempre tus cambios en un operador ($set, $inc, etc.).

Filtrar por _id requiere un ObjectId. Los IDs de los documentos se almacenan como objetos ObjectId, no como cadenas de texto simples:

from bson.objectid import ObjectId

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

Pasar el ID como una cadena de texto simple no coincidirá con nada y no hará nada silenciosamente.

Próximos Pasos

Was this page helpful?