W3docs

MongoDB Update

Lerne, wie du MongoDB-Dokumente in Python mit update_one(), update_many(), upsert und Operatoren wie $set, $inc und $push aktualisierst.

PyMongo bietet zwei zentrale Methoden zum Ändern von Dokumenten in einer Collection: update_one() ändert das erste Dokument, das einem Filter entspricht, und update_many() ändert jedes übereinstimmende Dokument. Beide Methoden verwenden die Update-Operatoren von MongoDB — Anweisungen wie $set, $inc und $push —, um genau zu beschreiben, was geändert werden soll, während der Rest des Dokuments unberührt bleibt.

Dieses Kapitel behandelt:

  • Verbindung zu MongoDB mit PyMongo herstellen
  • update_one() — ein einzelnes Dokument ändern
  • update_many() — viele Dokumente auf einmal ändern
  • Update-Operatoren: $set, $unset, $inc, $push, $pull
  • Verschachtelte Felder mit Punktnotation aktualisieren
  • Upserts — Einfügen oder Aktualisieren in einem Schritt
  • Überprüfen, was mit dem Ergebnisobjekt geändert wurde

Falls du noch keine Dokumente eingefügt hast, lies zuerst MongoDB Insert. Informationen zur Filtersyntax findest du unter MongoDB Query.

Verbindung zu MongoDB herstellen

Installiere den Treiber, falls noch nicht geschehen:

pip install pymongo

Verbinde dich dann mit einer Datenbank und einer Collection:

import pymongo

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

MongoClient ist lazy — er öffnet keinen Socket, bis die erste Operation ausgeführt wird. Die Datenbank und die Collection werden automatisch erstellt, wenn zum ersten Mal ein Dokument in sie geschrieben wird.

Ein einzelnes Dokument aktualisieren

update_one(filter, update) findet das erste Dokument, das filter entspricht, und wendet update darauf an.

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

Der $set-Operator überschreibt die aufgelisteten Felder und lässt jedes andere Feld im Dokument genau so, wie es war. Ohne $set würde das zweite Argument das gesamte Dokument ersetzen, was selten gewünscht ist.

Warum matched_count und modified_count unterschiedlich sein können

Wenn das Dokument bereits age: 31 enthält, findet MongoDB es, schreibt aber nichts. In diesem Fall ist matched_count gleich 1 und modified_count gleich 0. Prüfe immer modified_count, um sicherzustellen, dass ein echter Schreibvorgang stattgefunden hat.

Mehrere Dokumente aktualisieren

update_many(filter, update) wendet dieselbe Aktualisierung auf jedes Dokument an, das dem Filter entspricht.

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() ist pro Dokument atomar, aber nicht dokumentübergreifend. Jedes einzelne Dokument wird atomar geändert, aber andere Clients können zwischen den einzelnen Dokumentaktualisierungen innerhalb desselben update_many()-Aufrufs lesen oder schreiben.

Update-Operatoren

MongoDB bietet eine Reihe von Update-Operatoren, mit denen du Änderungen präzise ausdrücken kannst, ohne das gesamte Dokument über das Netzwerk zu senden.

$set — Feldwerte setzen

# 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 — ein Feld entfernen

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

Der Wert, den du dem Feld innerhalb von $unset zuweist, ist irrelevant — MongoDB ignoriert ihn. Konventionell wird ein leerer string verwendet.

$inc — eine Zahl inkrementieren oder dekrementieren

# 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 ist sicher für Zähler, da es sich um eine einzelne atomare Operation handelt — zwei gleichzeitige Inkrementierungen werden beide korrekt angewendet.

$push — an ein Array anhängen

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

$pull — Elemente aus einem Array entfernen

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

Verschachtelte Dokumente aktualisieren

Verwende die Punktnotation, um auf eingebettete Dokumente zuzugreifen, ohne das gesamte verschachtelte Objekt neu zu schreiben.

Betrachte ein Dokument mit dieser Struktur:

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

Um nur das Feld state innerhalb von address zu ändern:

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

Das Feld city innerhalb von address wird nicht berührt. Du kannst so viele Ebenen tief gehen, wie dein Schema es erfordert — zum Beispiel "address.geo.lat".

Upsert: Einfügen oder Aktualisieren in einem Schritt

Ein Upsert weist MongoDB an: „Aktualisiere dieses Dokument, wenn es existiert; füge es ein, wenn nicht." Übergebe upsert=True als Schlüsselwortargument:

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

Wenn MongoDB ein neues Dokument per Upsert einfügt, enthält das Attribut upserted_id des Ergebnisobjekts die neue _id. Wenn ein vorhandenes Dokument aktualisiert wird, ist upserted_id gleich None.

update_many() akzeptiert ebenfalls upsert=True. Wenn keine Dokumente übereinstimmen, fügt MongoDB ein neues Dokument ein — es werden niemals mehrere Dokumente aus einem einzigen Upsert eingefügt.

Das Ergebnisobjekt untersuchen

Sowohl update_one() als auch update_many() geben ein UpdateResult-Objekt mit drei nützlichen Attributen zurück:

AttributBeschreibung
matched_countAnzahl der Dokumente, die dem Filter entsprochen haben
modified_countAnzahl der Dokumente, die tatsächlich geändert wurden
upserted_id_id des neu eingefügten Dokuments (nur bei Upsert); andernfalls None
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}")

Häufige Fallstricke

Das Vergessen eines Update-Operators ersetzt das Dokument. Dieser Aufruf löscht alle Felder außer _id und ersetzt das Dokument durch nur age: 31:

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

Verpacke deine Änderungen immer in einen Operator ($set, $inc usw.).

Filtern nach _id erfordert ein ObjectId. Dokument-IDs werden als ObjectId-Objekte gespeichert, nicht als einfache Strings:

from bson.objectid import ObjectId

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

Wenn die ID als einfacher string übergeben wird, trifft sie nichts und tut stillschweigend nichts.

Nächste Schritte

Was this page helpful?