Requête MongoDB en Python : Filtres, Opérateurs et Projection
Apprenez à interroger MongoDB avec Python et pymongo — filtrez des documents, utilisez des opérateurs de comparaison et logiques, projetez des champs et paginez les résultats.
Ce chapitre explique comment construire des requêtes dans MongoDB à l'aide du pilote Python pymongo. Vous apprendrez à filtrer des documents avec des correspondances exactes et des opérateurs de comparaison, à combiner des conditions avec des opérateurs logiques, à sélectionner uniquement les champs dont vous avez besoin grâce à la projection, et à paginer les résultats avec skip() et limit().
Si vous n'avez pas encore configuré de connexion, consultez d'abord MongoDB Get Started et MongoDB Create Collection.
Configuration des données d'exemple
Tous les exemples de ce chapitre utilisent la même collection customers. Exécutez ce fragment une seule fois pour la remplir :
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.")Interroger tous les documents
Appeler find() avec un filtre vide ({}) renvoie tous les documents de la 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}
# ...Utilisez find_one() lorsque vous n'avez besoin que du premier document correspondant :
doc = col.find_one({"city": "London"})
print(doc)
# {'_id': ..., 'name': 'Alice', 'age': 30, 'city': 'London', 'score': 88}find_one() renvoie None si aucun document ne correspond — vérifiez toujours ce cas avant d'accéder aux champs.
Filtres de correspondance exacte
Passez un dictionnaire à find() pour trouver les documents où un champ est égal à une valeur spécifique :
# All customers in London
results = col.find({"city": "London"})
for doc in results:
print(doc["name"], doc["city"])
# Alice London
# Carol LondonPlusieurs clés dans le même dictionnaire de filtre agissent comme un ET implicite — les deux conditions doivent être vraies :
# 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 35Opérateurs de comparaison
Les opérateurs de comparaison MongoDB vous permettent de trouver des documents où un champ se situe dans une plage ou un ensemble donné. Tous les opérateurs sont préfixés par $.
| Opérateur | Signification | Exemple de filtre |
|---|---|---|
$eq | Égal à | {"age": {"$eq": 30}} |
$ne | Différent de | {"city": {"$ne": "London"}} |
$gt | Supérieur à | {"score": {"$gt": 80}} |
$gte | Supérieur ou égal | {"score": {"$gte": 80}} |
$lt | Inférieur à | {"age": {"$lt": 28}} |
$lte | Inférieur ou égal | {"age": {"$lte": 28}} |
$in | Dans une liste | {"city": {"$in": ["London", "Berlin"]}} |
$nin | Pas dans une liste | {"city": {"$nin": ["London"]}} |
Exemple — clients avec un score supérieur à 80 :
results = col.find({"score": {"$gt": 80}})
for doc in results:
print(doc["name"], doc["score"])
# Alice 88
# Carol 91Exemple — clients âgés de 25 à 30 ans (inclus) :
results = col.find({"age": {"$gte": 25, "$lte": 30}})
for doc in results:
print(doc["name"], doc["age"])
# Alice 30
# Bob 25
# Dave 28Vous pouvez combiner plusieurs opérateurs sur le même champ dans un seul dictionnaire, comme illustré ci-dessus.
Exemple — clients à Londres ou à Berlin :
results = col.find({"city": {"$in": ["London", "Berlin"]}})
for doc in results:
print(doc["name"], doc["city"])
# Alice London
# Carol London
# Dave BerlinOpérateurs logiques
Utilisez $and, $or et $nor lorsque vous avez besoin de combiner des conditions d'une manière que les clés de dictionnaire ordinaires ne peuvent pas exprimer.
$or — au moins une condition doit correspondre
# 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 — à utiliser lorsque deux opérateurs différents s'appliquent au même champ
Le ET implicite (clés multiples) ne fonctionne pas lorsque vous avez besoin de deux opérateurs $ sur le même champ. Utilisez plutôt $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 — aucune des conditions ne doit correspondre
# 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 — nier une expression de champ unique
$not enveloppe une expression d'opérateur unique et renvoie les documents pour lesquels la condition est fausse ou le champ n'existe pas :
# 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 77Filtres par expression régulière
Utilisez l'opérateur $regex (ou passez un modèle re compilé) pour effectuer une correspondance de sous-chaîne ou de motif sur des champs de type 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" rend la correspondance insensible à la casse. Évitez les motifs avec un joker en début de chaîne comme .*text sur de grandes collections — ils ne peuvent pas utiliser d'index et effectueront un balayage complet de la collection.
Projection — renvoyer uniquement des champs spécifiques
Par défaut, find() renvoie tous les champs du document, y compris _id. Utilisez un second argument (la projection) pour inclure ou exclure des champs.
Inclure des champs spécifiques
Passez 1 pour chaque champ souhaité. Seuls ces champs (plus _id) sont renvoyés :
# 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}
# ...Exclure des champs spécifiques
Passez 0 pour chaque champ à masquer. Tous les autres champs sont renvoyés :
# 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}
# ...Vous ne pouvez pas mélanger 1 et 0 dans la même projection (sauf pour _id, qui peut toujours être mis à 0 en même temps que des inclusions).
Trier les résultats
Enchaînez .sort() sur le curseur pour ordonner les résultats. Utilisez pymongo.ASCENDING (1) ou 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 65Passez une liste de tuples (champ, direction) pour trier selon plusieurs champs :
# 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 22Consultez MongoDB Sort pour un examen approfondi des options de tri.
Limiter et paginer les résultats
limit()
limit(n) arrête le curseur après avoir renvoyé n documents :
# 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 77skip() pour la pagination
Combinez skip() et limit() pour implémenter une navigation simple page par page :
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 74Pour les grandes collections, préférez la pagination basée sur des plages — filtrez sur le dernier _id vu ou un horodatage — car skip() parcourt quand même les documents ignorés en interne.
Consultez MongoDB Limit pour plus de détails.
Compter les documents
Utilisez count_documents() avec le même dictionnaire de filtre pour compter sans récupérer les données :
total = col.count_documents({})
london = col.count_documents({"city": "London"})
print(f"Total: {total}, In London: {london}")
# Total: 5, In London: 2Évitez le cursor.count() déprécié — il a été supprimé dans PyMongo 4.
Pièges courants
Les curseurs PyMongo sont épuisés après l'itération. Une fois que vous avez parcouru un curseur, il est vide. Stockez les résultats dans une liste si vous avez besoin d'itérer plusieurs fois :
docs = list(col.find({"city": "London"}))
print(len(docs)) # 2
print(docs[0]["name"]) # Alice_id est un ObjectId, pas une string. Si vous stockez un _id en tant que string et essayez ensuite de l'interroger, la requête ne renverra rien. Importez ObjectId depuis bson pour effectuer la conversion :
from bson import ObjectId
doc = col.find_one({"_id": ObjectId("665000000000000000000001")})Les requêtes sont sensibles à la casse par défaut. {"city": "london"} ne correspondra pas aux documents stockés avec "London". Utilisez $regex avec $options: "i" pour une correspondance insensible à la casse, ou normalisez les valeurs lors de l'insertion.
Prochaines étapes
- MongoDB Find —
find()etfind_one()en détail - MongoDB Sort — tri multi-champs et indicateurs d'index
- MongoDB Limit — contrôle de la taille des résultats
- MongoDB Update — modification des documents après les avoir trouvés
- MongoDB Delete — suppression de documents d'une collection