MongoDB
Guide d'administration MongoDB : installation, configuration, requêtes et réplication.
Concepts Clés
flowchart LR
subgraph "Structure MongoDB"
DB[(Database)] --> C1[Collection 1]
DB --> C2[Collection 2]
C1 --> D1[Document JSON]
C1 --> D2[Document JSON]
C2 --> D3[Document JSON]
end
| Concept SQL | Équivalent MongoDB |
|---|---|
| Database | Database |
| Table | Collection |
| Row | Document (JSON/BSON) |
| Column | Field |
| Primary Key | _id (automatique) |
| JOIN | $lookup / Embedding |
Installation
# Ajouter le repo MongoDB 7.0
cat << 'EOF' | sudo tee /etc/yum.repos.d/mongodb-org-7.0.repo
[mongodb-org-7.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/9/mongodb-org/7.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://pgp.mongodb.com/server-7.0.asc
EOF
# Installer MongoDB
sudo dnf install -y mongodb-org
# Démarrer et activer
sudo systemctl enable --now mongod
# Vérifier
mongosh --eval "db.runCommand({ping: 1})"
# Importer la clé GPG
curl -fsSL https://pgp.mongodb.com/server-7.0.asc | \
sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor
# Ajouter le repo (Ubuntu 22.04)
echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | \
sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
# Installer
sudo apt update
sudo apt install -y mongodb-org
# Démarrer
sudo systemctl enable --now mongod
Configuration
Fichier de Configuration
# /etc/mongod.conf
# Stockage
storage:
dbPath: /var/lib/mongo
journal:
enabled: true
wiredTiger:
engineConfig:
cacheSizeGB: 2 # 50% RAM - 1GB, ajuster selon serveur
# Logs
systemLog:
destination: file
logAppend: true
path: /var/log/mongodb/mongod.log
logRotate: reopen
# Réseau
net:
port: 27017
bindIp: 127.0.0.1 # localhost uniquement
# bindIp: 0.0.0.0 # Toutes les interfaces (avec auth!)
maxIncomingConnections: 1000
# Sécurité
security:
authorization: enabled # ACTIVER EN PRODUCTION
# Processus
processManagement:
timeZoneInfo: /usr/share/zoneinfo
fork: true
pidFilePath: /var/run/mongodb/mongod.pid
# Réplication (si replica set)
# replication:
# replSetName: rs0
Activer l'Authentification
# 1. Connexion sans auth (première fois)
mongosh
# 2. Créer l'admin
use admin
db.createUser({
user: "admin",
pwd: "strong_admin_password",
roles: [ { role: "userAdminAnyDatabase", db: "admin" }, "readWriteAnyDatabase" ]
})
# 3. Activer l'auth dans mongod.conf
# security:
# authorization: enabled
# 4. Redémarrer MongoDB
sudo systemctl restart mongod
# 5. Connexion avec auth
mongosh -u admin -p strong_admin_password --authenticationDatabase admin
Gestion des Utilisateurs
Créer des Utilisateurs
// Connexion admin
use admin
// Créer un utilisateur pour une base spécifique
use myapp_db
db.createUser({
user: "myapp_user",
pwd: "user_password",
roles: [
{ role: "readWrite", db: "myapp_db" }
]
})
// Utilisateur lecture seule
db.createUser({
user: "readonly_user",
pwd: "readonly_password",
roles: [
{ role: "read", db: "myapp_db" }
]
})
// Utilisateur avec accès à plusieurs bases
use admin
db.createUser({
user: "multi_db_user",
pwd: "password",
roles: [
{ role: "readWrite", db: "app1_db" },
{ role: "read", db: "app2_db" }
]
})
Rôles Principaux
| Rôle | Description |
|---|---|
read |
Lecture seule |
readWrite |
Lecture et écriture |
dbAdmin |
Administration de la base (index, stats) |
dbOwner |
Tous les droits sur la base |
userAdmin |
Gestion des utilisateurs |
clusterAdmin |
Administration du cluster |
root |
Superadmin (tout) |
Audit des Utilisateurs
// Lister tous les utilisateurs
use admin
db.getUsers()
// Voir les rôles d'un utilisateur
db.getUser("myapp_user")
// Modifier les rôles
db.updateUser("myapp_user", {
roles: [
{ role: "readWrite", db: "myapp_db" },
{ role: "read", db: "logs_db" }
]
})
// Supprimer un utilisateur
db.dropUser("old_user")
Opérations CRUD
Create (Insert)
use myapp_db
// Insérer un document
db.users.insertOne({
name: "John Doe",
email: "john@example.com",
age: 30,
roles: ["user", "admin"],
created_at: new Date()
})
// Insérer plusieurs documents
db.users.insertMany([
{ name: "Jane Doe", email: "jane@example.com", age: 28 },
{ name: "Bob Smith", email: "bob@example.com", age: 35 }
])
Read (Find)
// Tous les documents
db.users.find()
// Avec filtre
db.users.find({ age: { $gte: 30 } })
// Un seul document
db.users.findOne({ email: "john@example.com" })
// Projection (champs spécifiques)
db.users.find({}, { name: 1, email: 1, _id: 0 })
// Tri et limite
db.users.find().sort({ age: -1 }).limit(10)
// Comptage
db.users.countDocuments({ age: { $gte: 30 } })
Opérateurs de Requête
// Comparaison
db.users.find({ age: { $eq: 30 } }) // Égal
db.users.find({ age: { $ne: 30 } }) // Différent
db.users.find({ age: { $gt: 25 } }) // Plus grand
db.users.find({ age: { $gte: 25 } }) // Plus grand ou égal
db.users.find({ age: { $lt: 40 } }) // Plus petit
db.users.find({ age: { $lte: 40 } }) // Plus petit ou égal
db.users.find({ age: { $in: [25, 30, 35] } }) // Dans la liste
// Logiques
db.users.find({ $and: [{ age: { $gte: 25 } }, { age: { $lte: 35 } }] })
db.users.find({ $or: [{ age: 25 }, { age: 30 }] })
db.users.find({ age: { $not: { $gt: 30 } } })
// Tableaux
db.users.find({ roles: "admin" }) // Contient "admin"
db.users.find({ roles: { $all: ["user", "admin"] } }) // Contient tous
db.users.find({ roles: { $size: 2 } }) // Taille exacte
// Existence
db.users.find({ phone: { $exists: true } })
// Regex
db.users.find({ name: { $regex: /^John/i } })
Update
// Mettre à jour un document
db.users.updateOne(
{ email: "john@example.com" },
{ $set: { age: 31, updated_at: new Date() } }
)
// Mettre à jour plusieurs documents
db.users.updateMany(
{ age: { $lt: 30 } },
{ $set: { category: "young" } }
)
// Incrémenter
db.users.updateOne(
{ email: "john@example.com" },
{ $inc: { login_count: 1 } }
)
// Ajouter à un tableau
db.users.updateOne(
{ email: "john@example.com" },
{ $push: { roles: "moderator" } }
)
// Retirer d'un tableau
db.users.updateOne(
{ email: "john@example.com" },
{ $pull: { roles: "admin" } }
)
// Upsert (insert si n'existe pas)
db.users.updateOne(
{ email: "new@example.com" },
{ $set: { name: "New User", age: 25 } },
{ upsert: true }
)
Delete
// Supprimer un document
db.users.deleteOne({ email: "john@example.com" })
// Supprimer plusieurs documents
db.users.deleteMany({ age: { $lt: 18 } })
// Supprimer tous les documents
db.users.deleteMany({})
// Supprimer la collection
db.users.drop()
Index
Création d'Index
// Index simple
db.users.createIndex({ email: 1 }) // 1 = ASC, -1 = DESC
// Index unique
db.users.createIndex({ email: 1 }, { unique: true })
// Index composé
db.users.createIndex({ last_name: 1, first_name: 1 })
// Index TTL (expiration automatique)
db.sessions.createIndex(
{ created_at: 1 },
{ expireAfterSeconds: 3600 } // Expire après 1 heure
)
// Index texte (full-text search)
db.articles.createIndex({ title: "text", content: "text" })
// Index partiel
db.users.createIndex(
{ email: 1 },
{ partialFilterExpression: { status: "active" } }
)
Gestion des Index
// Lister les index
db.users.getIndexes()
// Statistiques d'utilisation
db.users.aggregate([{ $indexStats: {} }])
// Supprimer un index
db.users.dropIndex("email_1")
// Supprimer tous les index (sauf _id)
db.users.dropIndexes()
// Analyser une requête
db.users.find({ email: "john@example.com" }).explain("executionStats")
Aggregation Framework
Pipeline Basique
db.orders.aggregate([
// Stage 1: Filtrer
{ $match: { status: "completed" } },
// Stage 2: Grouper
{ $group: {
_id: "$customer_id",
total_spent: { $sum: "$amount" },
order_count: { $sum: 1 },
avg_order: { $avg: "$amount" }
}},
// Stage 3: Trier
{ $sort: { total_spent: -1 } },
// Stage 4: Limiter
{ $limit: 10 }
])
Opérateurs d'Aggregation
// $lookup (équivalent JOIN)
db.orders.aggregate([
{ $lookup: {
from: "customers",
localField: "customer_id",
foreignField: "_id",
as: "customer_info"
}},
{ $unwind: "$customer_info" }
])
// $project (projection)
db.users.aggregate([
{ $project: {
full_name: { $concat: ["$first_name", " ", "$last_name"] },
email: 1,
year_of_birth: { $subtract: [{ $year: new Date() }, "$age"] }
}}
])
// $bucket (histogramme)
db.users.aggregate([
{ $bucket: {
groupBy: "$age",
boundaries: [0, 18, 30, 50, 100],
default: "Other",
output: { count: { $sum: 1 } }
}}
])
// $facet (multi-pipelines)
db.products.aggregate([
{ $facet: {
by_category: [
{ $group: { _id: "$category", count: { $sum: 1 } } }
],
price_stats: [
{ $group: {
_id: null,
avg_price: { $avg: "$price" },
max_price: { $max: "$price" }
}}
]
}}
])
Réplication (Replica Set)
Architecture

┌─────────────────────────────────────────────────────────┐
│ Replica Set │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ PRIMARY │────▶│SECONDARY│────▶│SECONDARY│ │
│ │ (R/W) │ │ (Read) │ │ (Read) │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │ │ │
│ └───────────────┴───────────────┘ │
│ Oplog Sync │
└─────────────────────────────────────────────────────────┘
Configuration Replica Set
# /etc/mongod.conf sur CHAQUE nœud
replication:
replSetName: rs0
net:
bindIp: 0.0.0.0
port: 27017
security:
authorization: enabled
keyFile: /etc/mongodb/keyfile # Authentification interne
# Générer le keyfile (sur un nœud, puis copier)
openssl rand -base64 756 > /etc/mongodb/keyfile
chmod 400 /etc/mongodb/keyfile
chown mongod:mongod /etc/mongodb/keyfile
Initialiser le Replica Set
// Sur le PRIMARY
mongosh
// Initialiser
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "mongo1.example.com:27017", priority: 2 },
{ _id: 1, host: "mongo2.example.com:27017", priority: 1 },
{ _id: 2, host: "mongo3.example.com:27017", priority: 1 }
]
})
// Vérifier le statut
rs.status()
// Voir la configuration
rs.conf()
// Ajouter un membre
rs.add("mongo4.example.com:27017")
// Ajouter un arbiter (vote sans données)
rs.addArb("arbiter.example.com:27017")
Monitoring Réplication
// Statut détaillé
rs.status()
// Lag de réplication
rs.printSecondaryReplicationInfo()
// Oplog info
rs.printReplicationInfo()
// Forcer une élection (si PRIMARY down)
rs.stepDown()
Sauvegarde et Restauration
mongodump / mongorestore
# Sauvegarder toutes les bases
mongodump --uri="mongodb://admin:password@localhost:27017" \
--out=/backup/mongodb/$(date +%Y%m%d)
# Sauvegarder une base spécifique
mongodump --uri="mongodb://admin:password@localhost:27017/myapp_db" \
--out=/backup/mongodb/myapp_$(date +%Y%m%d)
# Avec compression
mongodump --uri="mongodb://admin:password@localhost:27017" \
--gzip --archive=/backup/mongodb/full_$(date +%Y%m%d).gz
# Restaurer
mongorestore --uri="mongodb://admin:password@localhost:27017" \
/backup/mongodb/20241130/
# Restaurer une base spécifique
mongorestore --uri="mongodb://admin:password@localhost:27017" \
--nsInclude="myapp_db.*" \
/backup/mongodb/20241130/
# Restaurer depuis archive compressée
mongorestore --uri="mongodb://admin:password@localhost:27017" \
--gzip --archive=/backup/mongodb/full_20241130.gz
Script de Backup
#!/bin/bash
# /opt/scripts/mongo_backup.sh
BACKUP_DIR="/backup/mongodb"
RETENTION_DAYS=7
DATE=$(date +%Y%m%d_%H%M%S)
MONGO_URI="mongodb://backup_user:password@localhost:27017"
mkdir -p "$BACKUP_DIR"
echo "Starting MongoDB backup..."
mongodump --uri="$MONGO_URI" \
--gzip \
--archive="$BACKUP_DIR/full_$DATE.gz"
if [ $? -eq 0 ]; then
echo "✓ Backup completed: full_$DATE.gz"
# Nettoyage
find "$BACKUP_DIR" -name "*.gz" -mtime +$RETENTION_DAYS -delete
else
echo "✗ Backup failed"
exit 1
fi
Monitoring
Commandes de Diagnostic
// Statut du serveur
db.serverStatus()
// Statistiques de la base
db.stats()
// Statistiques d'une collection
db.users.stats()
// Opérations en cours
db.currentOp()
// Tuer une opération
db.killOp(<opId>)
// Profiler (requêtes lentes)
db.setProfilingLevel(1, { slowms: 100 }) // Log requêtes > 100ms
db.system.profile.find().sort({ ts: -1 }).limit(10)
Métriques Importantes
// Connexions
db.serverStatus().connections
// Mémoire
db.serverStatus().mem
db.serverStatus().wiredTiger.cache
// Opérations
db.serverStatus().opcounters
// Réplication lag
rs.printSecondaryReplicationInfo()
Logs
# Voir les logs
tail -f /var/log/mongodb/mongod.log
# Rotation des logs
mongosh --eval "db.adminCommand({ logRotate: 1 })"
# Changer le niveau de log
mongosh --eval "db.setLogLevel(1, 'query')" # 0-5
Sécurité
Checklist
- [ ] Authentification activée (
security.authorization: enabled) - [ ] Bind IP restreint (pas 0.0.0.0 sans auth)
- [ ] Utilisateurs avec privilèges minimaux
- [ ] KeyFile pour replica set
- [ ] TLS/SSL pour les connexions distantes
- [ ] Firewall (port 27017)
- [ ] Audit logging activé (Enterprise)
Configuration TLS
# /etc/mongod.conf
net:
tls:
mode: requireTLS
certificateKeyFile: /etc/mongodb/server.pem
CAFile: /etc/mongodb/ca.pem
# Connexion TLS
mongosh --tls \
--tlsCAFile /etc/mongodb/ca.pem \
--tlsCertificateKeyFile /etc/mongodb/client.pem \
"mongodb://localhost:27017"
Voir Aussi
- PostgreSQL - Base relationnelle
- Redis - Cache et sessions
- Haute Disponibilité - Architectures HA
- Concepts BDD - Types de bases de données