W3docs

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 pymongo

Tous 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 34

Filtrer 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
# Carol

Projections — 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 1 pour inclure un champ, 0 pour 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érateurSignificationExemple
$eqÉgal (par défaut){"age": {"$eq": 34}}
$neDifférent{"city": {"$ne": "Paris"}}
$gtSupérieur à{"age": {"$gt": 30}}
$gteSupérieur ou égal à{"age": {"$gte": 34}}
$ltInférieur à{"age": {"$lt": 30}}
$lteInférieur ou égal à{"age": {"$lte": 28}}
$inValeur dans la liste{"city": {"$in": ["London", "Berlin"]}}
$ninValeur 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 (ou 1) — A → Z, du plus petit au plus grand
  • pymongo.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)  # True

Erreurs 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 like

find_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
Was this page helpful?