MongoDB Find
Apprenez à récupérer des documents MongoDB avec Python via find_one(), find(), les projections, les opérateurs de requête, sort, skip et limit.
Ce chapitre explique comment récupérer des documents d'une collection MongoDB en utilisant le pilote Python pymongo. Vous apprendrez les méthodes find_one() et find(), comment filtrer les résultats avec des opérateurs de requête, comment contrôler les champs retournés avec les projections, et comment trier, ignorer et limiter les résultats.
Configuration
Assurez-vous que pymongo est installé avant d'exécuter n'importe quel exemple :
pip install pymongoTous les exemples ci-dessous supposent un serveur MongoDB actif à l'adresse mongodb://localhost:27017/. Pour suivre sur votre propre machine, démarrez MongoDB avec mongod ou utilisez un cluster cloud gratuit (MongoDB Atlas).
Préparation des données d'exemple
Les exemples de ce chapitre utilisent une collection customers contenant ces cinq documents. Exécutez ceci une fois pour la remplir :
import pymongo
client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["mydatabase"]
col = db["customers"]
# Insert sample documents (skip if already inserted)
col.drop() # start fresh
col.insert_many([
{"name": "Alice", "age": 28, "city": "London"},
{"name": "Bob", "age": 34, "city": "Paris"},
{"name": "Carol", "age": 22, "city": "London"},
{"name": "David", "age": 40, "city": "Berlin"},
{"name": "Eve", "age": 34, "city": "Paris"},
])
print("Sample data ready.")Résultat attendu :
Sample data ready.PyMongo ajoute automatiquement un champ _id unique (un bson.ObjectId) à chaque document qui n'en possède pas déjà un.
Récupérer un seul document avec find_one()
find_one() retourne le premier document correspondant au filtre, ou None si aucun document ne correspond. C'est le bon choix lorsque vous attendez exactement un résultat (par exemple, rechercher un utilisateur par e-mail).
# Retrieve the first document in the collection
doc = col.find_one()
print(doc)
# {'_id': ObjectId('...'), 'name': 'Alice', 'age': 28, 'city': 'London'}Passez un filtre pour correspondre à un document spécifique :
# Find the customer named Bob
bob = col.find_one({"name": "Bob"})
print(bob)
# {'_id': ObjectId('...'), 'name': 'Bob', 'age': 34, 'city': 'Paris'}Si aucun document ne correspond, find_one() retourne None, donc pensez toujours à vous en prémunir :
result = col.find_one({"name": "Zara"})
if result is None:
print("No document found.")Récupérer plusieurs documents avec find()
find() retourne un curseur — un itérateur paresseux sur tous les documents correspondants. Rien n'est récupéré du serveur tant que vous n'itérez pas.
Récupérer tous les documents
# Iterate every document in the collection
for doc in col.find():
print(doc["name"], doc["age"])Résultat attendu (l'ordre peut varier sans tri explicite) :
Alice 28
Bob 34
Carol 22
David 40
Eve 34Filtrer avec une correspondance exacte
Passez un dictionnaire comme premier argument à find() :
# All customers in London
for doc in col.find({"city": "London"}):
print(doc["name"])
# Alice
# CarolProjections — Choisir les champs à retourner
Par défaut, MongoDB retourne chaque champ, y compris _id. Une projection vous permet d'inclure ou d'exclure des champs spécifiques, ce qui réduit le trafic réseau et l'utilisation de la mémoire.
Passez la projection comme deuxième argument positionnel (ou argument nommé projection) :
# Return only name and city; suppress _id
for doc in col.find({}, {"_id": 0, "name": 1, "city": 1}):
print(doc)
# {'name': 'Alice', 'city': 'London'}
# {'name': 'Bob', 'city': 'Paris'}
# ...Règles pour les projections :
- Utilisez
1pour inclure un champ,0pour l'exclure. - Vous ne pouvez pas mélanger inclusion et exclusion dans la même projection, sauf pour
_id(qui peut toujours être explicitement défini à0).
Opérateurs de requête
MongoDB fournit un ensemble riche d'opérateurs pour filtrer les documents. Passez-les à l'intérieur du dictionnaire de filtre.
Opérateurs de comparaison
| Opérateur | Signification | Exemple |
|---|---|---|
$eq | Égal (par défaut) | {"age": {"$eq": 34}} |
$ne | Différent | {"city": {"$ne": "Paris"}} |
$gt | Supérieur à | {"age": {"$gt": 30}} |
$gte | Supérieur ou égal à | {"age": {"$gte": 34}} |
$lt | Inférieur à | {"age": {"$lt": 30}} |
$lte | Inférieur ou égal à | {"age": {"$lte": 28}} |
$in | Valeur dans la liste | {"city": {"$in": ["London", "Berlin"]}} |
$nin | Valeur absente de la liste | {"city": {"$nin": ["Paris"]}} |
Exemple — clients de plus de 30 ans :
for doc in col.find({"age": {"$gt": 30}}, {"_id": 0, "name": 1, "age": 1}):
print(doc)
# {'name': 'Bob', 'age': 34}
# {'name': 'David', 'age': 40}
# {'name': 'Eve', 'age': 34}Exemple — clients à Londres ou Berlin :
for doc in col.find(
{"city": {"$in": ["London", "Berlin"]}},
{"_id": 0, "name": 1, "city": 1}
):
print(doc)
# {'name': 'Alice', 'city': 'London'}
# {'name': 'Carol', 'city': 'London'}
# {'name': 'David', 'city': 'Berlin'}Opérateurs logiques
ET implicite — fournir plusieurs clés dans un seul dictionnaire de filtre signifie que toutes les conditions doivent correspondre :
# Age > 30 AND city is Paris
for doc in col.find({"age": {"$gt": 30}, "city": "Paris"}, {"_id": 0}):
print(doc)
# {'name': 'Bob', 'age': 34, 'city': 'Paris'}
# {'name': 'Eve', 'age': 34, 'city': 'Paris'}$and est requis lorsque vous devez appliquer deux conditions différentes au même champ :
# Age between 28 (inclusive) and 40 (exclusive)
query = {"$and": [{"age": {"$gte": 28}}, {"age": {"$lt": 40}}]}
for doc in col.find(query, {"_id": 0, "name": 1, "age": 1}):
print(doc)
# {'name': 'Alice', 'age': 28}
# {'name': 'Bob', 'age': 34}
# {'name': 'Eve', 'age': 34}$or — au moins une condition doit correspondre :
# City is Berlin OR age is 22
for doc in col.find(
{"$or": [{"city": "Berlin"}, {"age": 22}]},
{"_id": 0, "name": 1}
):
print(doc)
# {'name': 'Carol'}
# {'name': 'David'}Correspondance de motifs avec $regex
Utilisez $regex pour faire correspondre des champs de type string à une expression régulière :
# Names that start with the letter 'C' or 'E' (case-sensitive)
for doc in col.find({"name": {"$regex": "^[CE]"}}, {"_id": 0, "name": 1}):
print(doc)
# {'name': 'Carol'}
# {'name': 'Eve'}Pour une correspondance insensible à la casse, ajoutez $options: "i" :
for doc in col.find(
{"city": {"$regex": "london", "$options": "i"}},
{"_id": 0, "name": 1, "city": 1}
):
print(doc)
# {'name': 'Alice', 'city': 'London'}
# {'name': 'Carol', 'city': 'London'}Trier les résultats
Chaînez .sort() sur le curseur. Passez le nom du champ et une constante de direction :
pymongo.ASCENDING(ou1) — A → Z, du plus petit au plus grandpymongo.DESCENDING(ou-1) — Z → A, du plus grand au plus petit
# Sort by age ascending
for doc in col.find({}, {"_id": 0, "name": 1, "age": 1}).sort("age", pymongo.ASCENDING):
print(doc)
# {'name': 'Carol', 'age': 22}
# {'name': 'Alice', 'age': 28}
# {'name': 'Bob', 'age': 34}
# {'name': 'Eve', 'age': 34}
# {'name': 'David', 'age': 40}Triez sur plusieurs champs en passant une liste de tuples (champ, direction) :
# Sort by age descending, then by name ascending (tiebreak)
order = [("age", pymongo.DESCENDING), ("name", pymongo.ASCENDING)]
for doc in col.find({}, {"_id": 0, "name": 1, "age": 1}).sort(order):
print(doc)
# {'name': 'David', 'age': 40}
# {'name': 'Bob', 'age': 34}
# {'name': 'Eve', 'age': 34}
# {'name': 'Alice', 'age': 28}
# {'name': 'Carol', 'age': 22}Limiter les résultats
.limit(n) plafonne le nombre de documents retournés. C'est utile pour afficher les N premiers résultats.
# Top 3 youngest customers
for doc in col.find({}, {"_id": 0, "name": 1, "age": 1}).sort("age", 1).limit(3):
print(doc)
# {'name': 'Carol', 'age': 22}
# {'name': 'Alice', 'age': 28}
# {'name': 'Bob', 'age': 34}Ignorer des documents (Pagination)
.skip(n) ignore les n premiers documents. Combiné avec .limit(), il permet la pagination par pages :
PAGE_SIZE = 2
def get_page(page_number):
"""Return one page of customers sorted by age (page_number is 0-indexed)."""
return list(
col.find({}, {"_id": 0, "name": 1, "age": 1})
.sort("age", pymongo.ASCENDING)
.skip(page_number * PAGE_SIZE)
.limit(PAGE_SIZE)
)
print(get_page(0)) # [{'name': 'Carol', 'age': 22}, {'name': 'Alice', 'age': 28}]
print(get_page(1)) # [{'name': 'Bob', 'age': 34}, {'name': 'Eve', 'age': 34}]
print(get_page(2)) # [{'name': 'David', 'age': 40}]Pour les grandes collections, préférez la pagination par curseur (filtrer par le dernier _id vu) plutôt que skip(), car skip() doit parcourir et ignorer des documents, ce qui devient lent à mesure que le décalage augmente.
Compter les documents correspondants
Utilisez count_documents() avec un filtre pour compter les correspondances sans récupérer les documents :
london_count = col.count_documents({"city": "London"})
print(london_count) # 2
total = col.count_documents({})
print(total) # 5Évitez l'ancienne méthode .count() sur les curseurs — elle a été dépréciée dans PyMongo 3.7 et supprimée dans PyMongo 4.
Vérifier si un document existe
Lorsque vous avez seulement besoin de savoir si au moins un document correspond, utilisez find_one() (moins coûteux que de compter) :
exists = col.find_one({"city": "Berlin"}) is not None
print(exists) # TrueErreurs courantes
Le curseur est épuisé après une seule itération. Si vous itérez le même curseur deux fois, la deuxième boucle ne produit rien. Appelez find() à nouveau ou convertissez en liste :
cursor = col.find({"city": "Paris"})
results = list(cursor) # materialise once
print(len(results)) # 2
# Now you can iterate `results` as many times as you likefind_one() vs find() — choisissez le bon. Si vous savez qu'il y a au plus une correspondance (par exemple, en interrogeant par un champ unique tel que l'e-mail), utilisez find_one(). Utiliser find() vous oblige à itérer même lorsque vous n'avez besoin que d'un seul résultat.
Filtre None vs dictionnaire vide. find() et find({}) retournent tous les documents. Évitez de passer None explicitement — utilisez {} pour plus de clarté.
Chapitres associés
- MongoDB Insert — insérer des documents dans une collection avant de les interroger
- MongoDB Query — couverture approfondie des expressions de requête et des patterns de filtrage
- MongoDB Sort — couverture dédiée du tri sur plusieurs champs
- MongoDB Limit — limit et son interaction avec les index
- MongoDB Update — modifier des documents que vous avez trouvés
- MongoDB Delete — supprimer des documents correspondants