MongoDB
La base de données NoSQL « orientée document » la plus connue. Stocke des documents JSON (BSON en interne) plutôt que des lignes de tables — utile quand le schéma varie d'un enregistrement à l'autre et qu'on veut éviter les jointures complexes.
À quoi ça sert
Une base relationnelle (Postgres, SQLite) structure les données en tables avec colonnes typées. C'est parfait quand le schéma est stable et qu'on a beaucoup de relations entre objets. Mais ça devient pénible quand :
- Chaque enregistrement a des champs différents (ex : journaux d'événements hétérogènes, configurations utilisateur).
- Le schéma évolue souvent et qu'on veut éviter une migration pour chaque ajout de champ.
- On manipule des structures imbriquées (objets dans objets, listes d'objets) qui demanderaient plein de tables jointes en SQL.
MongoDB stocke un document (en gros, un dict Python / un objet JSON) dans une collection (équivalent d'une table, mais sans schéma figé). On y stocke directement la structure qu'on a en mémoire, sans découper ni recoller.
En 2026, Postgres a rattrapé l'essentiel grâce au
type JSONB : tu peux stocker du JSON imbriqué, le
requêter, l'indexer. Du coup, le besoin pour MongoDB s'est réduit.
Mongo reste pertinent pour : énormément de documents
hétérogènes (logs d'événements à grande échelle),
équipes habituées à Mongo, ou
scaling horizontal facile (sharding natif).
Pour un projet MLOps classique, Postgres est plus simple — Mongo
a sa place sur des cas spécifiques.
Un exemple d'usage
Tu stockes les événements d'utilisation d'une application : chaque event a un type, un user, un timestamp, et un payload qui dépend du type. Schéma figé impossible — Mongo est confortable :
from pymongo import MongoClient
from datetime import datetime, timezone
client = MongoClient("mongodb://localhost:27017")
db = client["analytics"]
events = db["events"]
# Insérer des documents — pas besoin de CREATE TABLE
events.insert_one({
"user_id": "u_42",
"type": "login",
"ts": datetime.now(timezone.utc),
"ip": "203.0.113.7",
})
events.insert_one({
"user_id": "u_42",
"type": "purchase",
"ts": datetime.now(timezone.utc),
"items": [{"sku": "A", "qty": 2}, {"sku": "B", "qty": 1}],
"total": 42.50,
})
# Requêter : toutes les actions de u_42 dans les dernières 24h
from datetime import timedelta
recent = events.find({
"user_id": "u_42",
"ts": {"$gte": datetime.now(timezone.utc) - timedelta(days=1)},
})
for evt in recent:
print(evt)
Les deux documents n'ont pas les mêmes champs (ip vs
items + total) — c'est attendu en Mongo,
là où Postgres demanderait soit un JSONB soit deux
tables séparées.
How-to : installer et utiliser MongoDB
-
Lancer un MongoDB en local (Docker)
Comme pour PostgreSQL, l'image officielle Docker est la voie royale :
bashdocker run -d --name mongo \ -e MONGO_INITDB_ROOT_USERNAME=admin \ -e MONGO_INITDB_ROOT_PASSWORD=secret \ -p 27017:27017 \ -v mongodata:/data/db \ mongo:8Volume monté : indispensable pour persister les données entre redémarrages du conteneur.
-
Installer le client Python
pymongoest le driver officiel. Avec UV :bashuv add pymongoPour de l'async (FastAPI…), il y a
motorqui expose la même API en asynchrone. -
Se connecter
pythonfrom pymongo import MongoClient # URL complète (format MongoDB) client = MongoClient("mongodb://admin:secret@localhost:27017") # Hiérarchie : client > database > collection db = client["projet_devia"] users = db["users"] # Ping pour vérifier que ça répond print(client.server_info()["version"])Note : Mongo crée la database et la collection au premier insert. Pas besoin d'un
CREATE DATABASE. -
Insérer des documents
python# Un document = un dict Python users.insert_one({"name": "Alice", "age": 30, "tags": ["admin"]}) # Insertion en lot (plus rapide) users.insert_many([ {"name": "Bob", "age": 25}, {"name": "Carol", "age": 35, "tags": ["member"]}, ])Mongo ajoute automatiquement un champ
_id(un ObjectId unique) à chaque document. C'est l'équivalentPRIMARY KEYSQL. -
Requêter
Les requêtes Mongo sont elles-mêmes des dicts. Les opérateurs commencent par
$:python# Un seul document users.find_one({"name": "Alice"}) # Plusieurs (renvoie un curseur, on l'itère) for u in users.find({"age": {"$gte": 30}}): print(u) # Opérateurs de comparaison users.find({"age": {"$gt": 18, "$lt": 65}}) # Recherche dans un tableau users.find({"tags": "admin"}) # Projection : ne ramener que certains champs users.find({}, {"name": 1, "_id": 0}) # Tri / limite users.find().sort("age", -1).limit(5) -
Mettre à jour, supprimer
python# Update : opérateurs $set, $inc, $push… users.update_one( {"name": "Alice"}, {"$set": {"age": 31}, "$push": {"tags": "vip"}} ) # Upsert : insère si pas trouvé, sinon update users.update_one( {"name": "Dave"}, {"$set": {"age": 40}}, upsert=True, ) # Suppression users.delete_one({"name": "Bob"}) users.delete_many({"age": {"$lt": 18}}) -
Agréger (pipeline)
L'équivalent du
GROUP BYSQL en Mongo se fait via le aggregation framework — un pipeline d'étapes :pythonpipeline = [ {"$match": {"type": "purchase"}}, {"$group": { "_id": "$user_id", "total": {"$sum": "$total"}, "n_purchases": {"$sum": 1}, }}, {"$sort": {"total": -1}}, {"$limit": 10}, ] for row in events.aggregate(pipeline): print(row) -
Créer des index
Comme en SQL, un index accélère les requêtes répétées sur un champ. À créer une seule fois :
pythonusers.create_index("name") # asc users.create_index([("age", -1)]) # desc users.create_index("email", unique=True) # unicitéPenser aux index dès le débutSans index, une requête sur 1M de documents fait un scan complet (lent). Pour chaque champ qui sert régulièrement de filtre, ajoute un index — même règle qu'en PostgreSQL.
Aide-mémoire
from pymongo import MongoClient
client = MongoClient("mongodb://user:pwd@host:27017")
col = client["db"]["collection"]
col.insert_one({...}); col.insert_many([{...}, …])
col.find_one({"k": "v"}); col.find({...})
col.update_one({...}, {"$set": {...}})
col.delete_one({...}); col.delete_many({...})
{"age": {"$gte": 18, "$lt": 65}}
{"tags": {"$in": ["a", "b"]}}
{"name": {"$regex": "^Al"}}
{"$and": [{...}, {...}]}; {"$or": [{...}, {...}]}
col.aggregate([
{"$match": {...}},
{"$group": {"_id": "$field", "n": {"$sum": 1}}},
{"$sort": {"n": -1}},
])
MongoDB et le reste de l'écosystème
- PostgreSQL — le choix « par défaut » concurrent. Postgres + JSONB couvre 80% des cas où on aurait pensé à Mongo, avec en bonus le SQL et les contraintes d'intégrité. Mongo gagne en simplicité d'usage quand les documents sont vraiment hétérogènes et nombreux.
-
Docker — l'image
officielle
mongotourne partout, avec undocker-compose.ymlà côté du backend. - FastAPI — combo cohérent : pymongo (sync) ou motor (async) pour parler à Mongo, Pydantic pour valider les documents entrants/sortants, FastAPI pour le routing.
- Pydantic — même en Mongo « sans schéma », on met de facto un schéma côté application avec Pydantic. La lib beanie (ODM) fait ça nativement, à la manière d'un SQLAlchemy pour Mongo.
- Prometheus / Grafana — Mongo expose des métriques que Prometheus peut scraper via un exporter, avec des dashboards Grafana tout faits.
- Redis — souvent associé à Mongo en cache : Mongo persiste, Redis cache les requêtes chaudes (latence sub-milliseconde).
Trois bonnes raisons : (1) tes documents sont vraiment hétérogènes et tu en as beaucoup (event logs, contenus d'apps mobiles…). (2) tu prévois un scaling horizontal massif (sharding natif Mongo est plus simple que celui de Postgres). (3) ton équipe maîtrise déjà Mongo. Sinon, prends Postgres — le JSONB règle la plupart des « besoins NoSQL » sans changer de stack.
Pour aller plus loin
- Site officiel : mongodb.com
- Manuel : mongodb.com/docs/manual
- Driver Python pymongo : pymongo.readthedocs.io
- Beanie (ODM Pydantic + Mongo) : beanie-odm.dev
- MongoDB University (cours gratuits) : learn.mongodb.com