W3docs

MongoDB-Abfragen in Python: Filter, Operatoren & Projektion

MongoDB mit Python und pymongo abfragen — Dokumente filtern, Vergleichs- und logische Operatoren nutzen, Felder projizieren und Ergebnisse paginieren.

Dieses Kapitel erklärt, wie man Abfragen in MongoDB mit dem Python-Treiber pymongo erstellt. Sie lernen, Dokumente mit exakten Übereinstimmungen und Vergleichsoperatoren zu filtern, Bedingungen mit logischen Operatoren zu kombinieren, nur die benötigten Felder per Projektion auszuwählen und Ergebnisse mit skip() und limit() zu paginieren.

Falls Sie noch keine Verbindung eingerichtet haben, lesen Sie zunächst MongoDB Get Started und MongoDB Create Collection.

Beispieldaten einrichten

Alle Beispiele in diesem Kapitel verwenden dieselbe customers-Collection. Führen Sie diesen Codeausschnitt einmal aus, um die Daten einzufügen:

import pymongo

client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["mystore"]
col = db["customers"]

# Drop and re-create so examples are repeatable
col.drop()
col.insert_many([
    {"name": "Alice", "age": 30, "city": "London",   "score": 88},
    {"name": "Bob",   "age": 25, "city": "New York",  "score": 74},
    {"name": "Carol", "age": 35, "city": "London",   "score": 91},
    {"name": "Dave",  "age": 28, "city": "Berlin",    "score": 65},
    {"name": "Eve",   "age": 22, "city": "New York",  "score": 77},
])
print("Sample data inserted.")

Alle Dokumente abfragen

Der Aufruf von find() mit einem leeren Filter ({}) gibt jedes Dokument der Collection zurück:

for doc in col.find({}):
    print(doc)
# {'_id': ..., 'name': 'Alice', 'age': 30, 'city': 'London',   'score': 88}
# {'_id': ..., 'name': 'Bob',   'age': 25, 'city': 'New York',  'score': 74}
# ...

Verwenden Sie find_one(), wenn Sie nur das erste übereinstimmende Dokument benötigen:

doc = col.find_one({"city": "London"})
print(doc)
# {'_id': ..., 'name': 'Alice', 'age': 30, 'city': 'London', 'score': 88}

find_one() gibt None zurück, wenn kein Dokument übereinstimmt — prüfen Sie das immer, bevor Sie auf Felder zugreifen.

Exakte Übereinstimmungsfilter

Übergeben Sie ein Dictionary an find(), um Dokumente zu finden, bei denen ein Feld einem bestimmten Wert entspricht:

# All customers in London
results = col.find({"city": "London"})
for doc in results:
    print(doc["name"], doc["city"])
# Alice London
# Carol London

Mehrere Schlüssel im selben Filter-Dictionary wirken als implizites AND — beide Bedingungen müssen wahr sein:

# Customers in London AND older than 30
results = col.find({"city": "London", "age": {"$gt": 30}})
for doc in results:
    print(doc["name"], doc["age"])
# Carol 35

Vergleichsoperatoren

MongoDB-Vergleichsoperatoren ermöglichen die Suche nach Dokumenten, bei denen ein Feld in einem bestimmten Bereich oder einer Menge liegt. Alle Operatoren beginnen mit $.

OperatorBedeutungBeispielfilter
$eqGleich{"age": {"$eq": 30}}
$neUngleich{"city": {"$ne": "London"}}
$gtGrößer als{"score": {"$gt": 80}}
$gteGrößer oder gleich{"score": {"$gte": 80}}
$ltKleiner als{"age": {"$lt": 28}}
$lteKleiner oder gleich{"age": {"$lte": 28}}
$inIn einer Liste{"city": {"$in": ["London", "Berlin"]}}
$ninNicht in einer Liste{"city": {"$nin": ["London"]}}

Beispiel — Kunden mit einem Score über 80:

results = col.find({"score": {"$gt": 80}})
for doc in results:
    print(doc["name"], doc["score"])
# Alice 88
# Carol 91

Beispiel — Kunden zwischen 25 und 30 Jahren (einschließlich):

results = col.find({"age": {"$gte": 25, "$lte": 30}})
for doc in results:
    print(doc["name"], doc["age"])
# Alice 30
# Bob   25
# Dave  28

Mehrere Operatoren können auf dasselbe Feld in einem einzigen Dictionary angewendet werden, wie oben gezeigt.

Beispiel — Kunden in London oder Berlin:

results = col.find({"city": {"$in": ["London", "Berlin"]}})
for doc in results:
    print(doc["name"], doc["city"])
# Alice London
# Carol London
# Dave  Berlin

Logische Operatoren

Verwenden Sie $and, $or und $nor, wenn Sie Bedingungen auf eine Weise kombinieren müssen, die mit einfachen Dictionary-Schlüsseln nicht möglich ist.

$or — mindestens eine Bedingung muss zutreffen

# Customers younger than 25 OR with a score above 90
results = col.find({"$or": [{"age": {"$lt": 25}}, {"score": {"$gt": 90}}]})
for doc in results:
    print(doc["name"], doc["age"], doc["score"])
# Carol 35 91
# Eve   22 77

$and — verwenden, wenn zwei verschiedene Operatoren auf dasselbe Feld angewendet werden

Das implizite AND (mehrere Schlüssel) funktioniert nicht, wenn Sie zwei $-Operatoren auf dasselbe Feld anwenden möchten. Verwenden Sie stattdessen $and:

# Customers whose score is > 65 AND < 90
# (cannot use {"score": {"$gt": 65}, "score": {"$lt": 90}} — duplicate key)
results = col.find({"$and": [{"score": {"$gt": 65}}, {"score": {"$lt": 90}}]})
for doc in results:
    print(doc["name"], doc["score"])
# Alice 88
# Bob   74
# Eve   77

$nor — keine der Bedingungen darf zutreffen

# Customers who are NOT in London AND do NOT have score > 80
results = col.find({"$nor": [{"city": "London"}, {"score": {"$gt": 80}}]})
for doc in results:
    print(doc["name"], doc["city"], doc["score"])
# Bob  New York 74
# Dave Berlin   65
# Eve  New York 77

$not — einen einzelnen Feldausdruck negieren

$not kapselt einen einzelnen Operatorausdruck und gibt Dokumente zurück, bei denen die Bedingung falsch ist oder das Feld nicht existiert:

# Customers who do NOT have a score greater than 80
results = col.find({"score": {"$not": {"$gt": 80}}})
for doc in results:
    print(doc["name"], doc["score"])
# Bob  74
# Dave 65
# Eve  77

Filter mit regulären Ausdrücken

Verwenden Sie den Operator $regex (oder übergeben Sie ein kompiliertes re-Muster), um Teilstring- oder Musterabgleiche auf string-Feldern durchzuführen:

import re

# Customers whose name starts with a vowel
results = col.find({"name": {"$regex": "^[AEIOU]", "$options": "i"}})
for doc in results:
    print(doc["name"])
# Alice
# Eve

$options: "i" macht den Abgleich case-insensitiv. Vermeiden Sie führende Wildcard-Muster wie .*text bei großen Collections — sie können keinen Index nutzen und führen zu einem vollständigen Collection-Scan.

Projektion — Nur bestimmte Felder zurückgeben

Standardmäßig gibt find() jedes Feld im Dokument zurück, einschließlich _id. Verwenden Sie ein zweites Argument (die Projektion), um Felder ein- oder auszuschließen.

Bestimmte Felder einschließen

Übergeben Sie 1 für jedes gewünschte Feld. Nur diese Felder (plus _id) werden zurückgegeben:

# Return only name and score
results = col.find({}, {"name": 1, "score": 1})
for doc in results:
    print(doc)
# {'_id': ..., 'name': 'Alice', 'score': 88}
# {'_id': ..., 'name': 'Bob',   'score': 74}
# ...

Bestimmte Felder ausschließen

Übergeben Sie 0 für jedes Feld, das ausgeblendet werden soll. Alle anderen Felder werden zurückgegeben:

# Hide _id and city
results = col.find({}, {"_id": 0, "city": 0})
for doc in results:
    print(doc)
# {'name': 'Alice', 'age': 30, 'score': 88}
# {'name': 'Bob',   'age': 25, 'score': 74}
# ...

In derselben Projektion können 1 und 0 nicht gemischt werden (außer bei _id, das immer zusammen mit Inklusionen auf 0 gesetzt werden kann).

Ergebnisse sortieren

Hängen Sie .sort() an den Cursor an, um Ergebnisse zu ordnen. Verwenden Sie pymongo.ASCENDING (1) oder pymongo.DESCENDING (-1):

import pymongo

# Sort by score descending
results = col.find({}, {"_id": 0, "name": 1, "score": 1}).sort("score", pymongo.DESCENDING)
for doc in results:
    print(doc["name"], doc["score"])
# Carol 91
# Alice 88
# Eve   77
# Bob   74
# Dave  65

Übergeben Sie eine Liste von (Feld, Richtung)-Tupeln, um nach mehreren Feldern zu sortieren:

# Sort by city ascending, then by age descending within each city
results = col.find({}, {"_id": 0, "name": 1, "city": 1, "age": 1}).sort(
    [("city", pymongo.ASCENDING), ("age", pymongo.DESCENDING)]
)
for doc in results:
    print(doc["city"], doc["name"], doc["age"])
# Berlin  Dave  28
# London  Carol 35
# London  Alice 30
# New York Bob   25   <- Bob (25) vs Eve (22): descending so 25 first
# New York Eve   22

Weitere Informationen zu Sortieroptionen finden Sie unter MongoDB Sort.

Ergebnisse begrenzen und paginieren

limit()

limit(n) stoppt den Cursor nach der Rückgabe von n Dokumenten:

# Top 3 by score
results = col.find({}, {"_id": 0, "name": 1, "score": 1}).sort("score", -1).limit(3)
for doc in results:
    print(doc["name"], doc["score"])
# Carol 91
# Alice 88
# Eve   77

skip() für die Paginierung

Kombinieren Sie skip() und limit(), um eine einfache seitenweise Navigation zu implementieren:

page_size = 2
page = 1  # zero-indexed

results = (
    col.find({}, {"_id": 0, "name": 1, "score": 1})
       .sort("score", -1)
       .skip(page * page_size)
       .limit(page_size)
)
for doc in results:
    print(doc["name"], doc["score"])
# Eve  77   (page 1, items 3–4 of the sorted list)
# Bob  74

Bei großen Collections empfiehlt sich die bereichsbasierte Paginierung — filtern Sie anhand der zuletzt gesehenen _id oder eines Zeitstempels — da skip() intern trotzdem über übersprungene Dokumente iteriert.

Weitere Details finden Sie unter MongoDB Limit.

Dokumente zählen

Verwenden Sie count_documents() mit demselben Filter-Dictionary, um Dokumente zu zählen, ohne Daten abzurufen:

total = col.count_documents({})
london = col.count_documents({"city": "London"})
print(f"Total: {total}, In London: {london}")
# Total: 5, In London: 2

Vermeiden Sie das veraltete cursor.count() — es wurde in PyMongo 4 entfernt.

Häufige Fehlerquellen

PyMongo-Cursor sind nach der Iteration erschöpft. Sobald Sie einen Cursor durchlaufen haben, ist er leer. Speichern Sie die Ergebnisse in einer Liste, wenn Sie mehr als einmal iterieren müssen:

docs = list(col.find({"city": "London"}))
print(len(docs))   # 2
print(docs[0]["name"])  # Alice

_id ist ein ObjectId, kein string. Wenn Sie eine _id als string speichern und später danach abfragen, gibt die Abfrage nichts zurück. Importieren Sie ObjectId aus bson, um zu konvertieren:

from bson import ObjectId

doc = col.find_one({"_id": ObjectId("665000000000000000000001")})

Abfragen sind standardmäßig case-sensitiv. {"city": "london"} stimmt nicht mit Dokumenten überein, die als "London" gespeichert sind. Verwenden Sie $regex mit $options: "i" für case-insensitiven Abgleich, oder normalisieren Sie Werte beim Einfügen.

Nächste Schritte

Was this page helpful?