W3docs

Query MongoDB in Python: Filtri, Operatori e Proiezione

Impara a interrogare MongoDB con Python e pymongo: filtra documenti, usa operatori di confronto e logici, proietta campi e pagina i risultati.

Questo capitolo spiega come costruire query in MongoDB usando il driver Python pymongo. Imparerai a filtrare documenti con corrispondenze esatte e operatori di confronto, combinare condizioni con operatori logici, selezionare solo i campi necessari con la proiezione e paginare i risultati con skip() e limit().

Se non hai ancora configurato una connessione, consulta prima MongoDB Get Started e MongoDB Create Collection.

Configurazione dei Dati di Esempio

Tutti gli esempi di questo capitolo usano la stessa collection customers. Esegui questo snippet una volta per popolarla:

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

Interrogare Tutti i Documenti

Chiamare find() con un filtro vuoto ({}) restituisce ogni documento della collection:

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}
# ...

Usa find_one() quando ti serve solo il primo documento corrispondente:

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

find_one() restituisce None se nessun documento corrisponde — controlla sempre questo caso prima di accedere ai campi.

Filtri a Corrispondenza Esatta

Passa un dizionario a find() per trovare i documenti in cui un campo equivale a un valore specifico:

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

Più chiavi nello stesso dizionario di filtro agiscono come un AND implicito — entrambe le condizioni devono essere vere:

# 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

Operatori di Confronto

Gli operatori di confronto di MongoDB ti permettono di trovare documenti in cui un campo rientra in un intervallo o in un insieme. Tutti gli operatori sono prefissati con $.

OperatoreSignificatoEsempio di filtro
$eqUguale a{"age": {"$eq": 30}}
$neDiverso da{"city": {"$ne": "London"}}
$gtMaggiore di{"score": {"$gt": 80}}
$gteMaggiore o uguale{"score": {"$gte": 80}}
$ltMinore di{"age": {"$lt": 28}}
$lteMinore o uguale{"age": {"$lte": 28}}
$inIn una lista{"city": {"$in": ["London", "Berlin"]}}
$ninNon in una lista{"city": {"$nin": ["London"]}}

Esempio — clienti con un punteggio superiore a 80:

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

Esempio — clienti di età compresa tra 25 e 30 (inclusi):

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

Puoi combinare più operatori sullo stesso campo all'interno di un unico dizionario, come mostrato sopra.

Esempio — clienti a London o Berlin:

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

Operatori Logici

Usa $and, $or e $nor quando hai bisogno di combinare condizioni in modi che le semplici chiavi di un dizionario non consentono.

$or — almeno una condizione deve corrispondere

# 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 — da usare quando si applicano due operatori diversi allo stesso campo

L'AND implicito (chiavi multiple) non funziona quando hai bisogno di due operatori $ sullo stesso campo. Usa invece $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 — nessuna delle condizioni deve corrispondere

# 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 — nega un'espressione su un singolo campo

$not racchiude un'espressione con operatore singolo e restituisce i documenti in cui la condizione è falsa oppure il campo non esiste:

# 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

Filtri con Espressioni Regolari

Usa l'operatore $regex (o passa un pattern re compilato) per effettuare ricerche per sottostringa o pattern sui campi string:

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" rende la corrispondenza insensibile alle maiuscole. Evita pattern con wildcard iniziale come .*text su collection di grandi dimensioni — non possono usare un indice e causeranno una scansione completa della collection.

Proiezione — Restituire Solo Campi Specifici

Per impostazione predefinita, find() restituisce ogni campo del documento, incluso _id. Usa un secondo argomento (la proiezione) per includere o escludere campi.

Includere campi specifici

Passa 1 per ogni campo desiderato. Vengono restituiti solo quei campi (più _id):

# 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}
# ...

Escludere campi specifici

Passa 0 per ogni campo da nascondere. Tutti gli altri campi vengono restituiti:

# 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}
# ...

Non puoi mescolare 1 e 0 nella stessa proiezione (fatta eccezione per _id, che può sempre essere impostato a 0 insieme alle inclusioni).

Ordinamento dei Risultati

Concatena .sort() al cursore per ordinare i risultati. Usa pymongo.ASCENDING (1) o 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

Passa una lista di tuple (campo, direzione) per ordinare per più campi:

# 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

Vedi MongoDB Sort per un approfondimento sulle opzioni di ordinamento.

Limitare e Paginare i Risultati

limit()

limit(n) interrompe il cursore dopo aver restituito n documenti:

# 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() per la paginazione

Combina skip() e limit() per implementare una semplice navigazione pagina per pagina:

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

Per collection di grandi dimensioni, preferisci la paginazione basata su intervalli — filtra sull'ultimo _id visto o su un timestamp — perché skip() scansiona comunque i documenti saltati internamente.

Vedi MongoDB Limit per ulteriori dettagli.

Contare i Documenti

Usa count_documents() con lo stesso dizionario di filtro per contare senza recuperare i dati:

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

Evita il metodo deprecato cursor.count() — è stato rimosso in PyMongo 4.

Errori Comuni

I cursori PyMongo si esauriscono dopo l'iterazione. Una volta che hai iterato su un cursore, è vuoto. Memorizza i risultati in una lista se hai bisogno di iterare più di una volta:

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

_id è un ObjectId, non una string. Se memorizzi un _id come string e poi provi a interrogare per esso, la query non restituirà nulla. Importa ObjectId da bson per convertirlo:

from bson import ObjectId

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

Le query sono sensibili alle maiuscole per impostazione predefinita. {"city": "london"} non corrisponderà ai documenti salvati come "London". Usa $regex con $options: "i" per la corrispondenza insensibile alle maiuscole, oppure normalizza i valori al momento dell'inserimento.

Passi Successivi

Was this page helpful?