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 documentoupdate_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 pymongoPoi 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 changedL'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:
| Attributo | Descrizione |
|---|---|
matched_count | Numero di documenti che hanno corrisposto al filtro |
modified_count | Numero 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
- MongoDB Delete — rimuovere documenti con
delete_one()edelete_many() - MongoDB Find — recuperare documenti e filtrare i risultati
- MongoDB Query — operatori di query avanzati e pattern