W3docs

Aggiornamento MongoDB

Scopri come aggiornare documenti MongoDB in Python con update_one(), update_many(), upsert e operatori come $set, $inc e $push.

PyMongo offre due metodi principali per modificare i documenti in una collection: update_one() modifica il primo documento che corrisponde a un filtro, mentre update_many() modifica tutti i documenti corrispondenti. Entrambi i metodi utilizzano gli operatori di aggiornamento di MongoDB — istruzioni come $set, $inc e $push — per descrivere esattamente cosa deve cambiare, lasciando invariato il resto del documento.

Questo capitolo tratta:

  • Connessione a MongoDB con PyMongo
  • update_one() — modificare un singolo documento
  • update_many() — modificare più documenti contemporaneamente
  • Operatori di aggiornamento: $set, $unset, $inc, $push, $pull
  • Aggiornamento di campi nidificati con la notazione a punto
  • Upsert — inserimento o aggiornamento in un unico passaggio
  • Verifica di ciò che è stato modificato tramite l'object risultato

Se non hai ancora inserito alcun documento, leggi prima MongoDB Insert. Per la sintassi di filtraggio, consulta MongoDB Query.

Connessione a MongoDB

Installa il driver se non lo hai già fatto:

pip install pymongo

Poi connettiti a un database e a una collection:

import pymongo

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

MongoClient è lazy — non apre effettivamente un socket fino alla prima operazione. Il database e la collection vengono creati automaticamente la prima volta che viene scritto un documento al loro interno.

Aggiornare un Singolo Documento

update_one(filter, update) trova il primo documento che corrisponde a filter e applica update ad esso.

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

L'operatore $set sovrascrive i campi elencati e lascia invariati tutti gli altri campi del documento. Senza $set, il secondo argomento sostituirebbe l'intero documento, il che raramente è il risultato desiderato.

Perché matched_count e modified_count possono differire

Se il documento ha già age: 31, MongoDB lo trova ma non scrive nulla. In questo caso matched_count è 1 e modified_count è 0. Controlla sempre modified_count per confermare che sia avvenuta una scrittura effettiva.

Aggiornare Più Documenti

update_many(filter, update) applica lo stesso aggiornamento a tutti i documenti che corrispondono al 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() è atomico per singolo documento ma non su tutti i documenti contemporaneamente. Ogni documento viene modificato atomicamente, ma altri client possono leggere o scrivere tra gli aggiornamenti dei singoli documenti all'interno della stessa chiamata update_many().

Operatori di Aggiornamento

MongoDB mette a disposizione un insieme di operatori di aggiornamento che consentono di esprimere le modifiche con precisione senza inviare l'intero documento sulla rete.

$set — impostare i valori dei campi

# 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 — rimuovere un campo

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

Il valore assegnato al campo all'interno di $unset è irrilevante — MongoDB lo ignora. La convenzione è utilizzare una stringa vuota.

$inc — incrementare o decrementare un numero

# 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 è sicuro per i contatori perché è una singola operazione atomica — due incrementi simultanei verranno entrambi applicati correttamente.

$push — aggiungere un elemento 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 — rimuovere elementi da un array

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

Aggiornare Documenti Nidificati

Usa la notazione a punto per accedere ai documenti incorporati senza riscrivere l'intero object nidificato.

Considera un documento con questa struttura:

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

Per modificare solo il campo state all'interno di address:

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

Il campo city all'interno di address non viene toccato. È possibile scendere tanti livelli quanto richiede lo schema — ad esempio "address.geo.lat".

Upsert: Inserimento o Aggiornamento in un Unico Passaggio

Un upsert indica a MongoDB: "aggiorna questo documento se esiste; inseriscilo se non esiste." Passa upsert=True come argomento keyword:

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 MongoDB inserisce un nuovo documento tramite upsert, l'attributo upserted_id dell'object risultato contiene il nuovo _id. Quando aggiorna un documento esistente, upserted_id è None.

Anche update_many() accetta upsert=True. Se nessun documento corrisponde, MongoDB inserisce un unico nuovo documento — non inserisce mai più documenti da un singolo upsert.

Analisi dell'Object Risultato

Sia update_one() che update_many() restituiscono un object UpdateResult con tre attributi utili:

AttributoDescrizione
matched_countNumero di documenti che hanno corrisposto al filtro
modified_countNumero di documenti effettivamente modificati
upserted_id_id del documento appena inserito (solo upsert); None altrimenti
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}")

Errori Comuni

Dimenticare un operatore di aggiornamento sostituisce il documento. Questa chiamata elimina tutti i campi tranne _id e sostituisce il documento con soltanto age: 31:

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

Racchiudi sempre le modifiche in un operatore ($set, $inc, ecc.).

Il filtraggio per _id richiede un ObjectId. Gli ID dei documenti sono memorizzati come object ObjectId, non come semplici stringhe:

from bson.objectid import ObjectId

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

Passare l'ID come stringa semplice non troverà alcuna corrispondenza e non farà nulla in modo silenzioso.

Passi Successivi

Was this page helpful?