Public cible
Débutants, étudiants et professionnels qui souhaitent acquérir une pratique structurée dans ce domaine.
Formation pratique sur MongoDB : notions, méthodes, ateliers et livrables vérifiables.
Débutants, étudiants et professionnels qui souhaitent acquérir une pratique structurée dans ce domaine.
Comprendre les notions essentielles et les appliquer dans un projet vérifiable.
Aucune connaissance préalable n’est strictement obligatoire ; les prérequis détaillés sont précisés dans les ateliers.
Tous niveaux
La validation repose sur les évaluations actives et les livrables pratiques du cours.
Un ordinateur, un navigateur et les outils indiqués dans le premier atelier sont suffisants pour commencer.
Concevoir un schéma documentaire et manipuler une collection.
Obligatoire ConsulterÉvaluer les requêtes, agrégations, indexations et transactions.
Obligatoire ConsulterDévelopper une API documentaire avec données de démonstration.
Livrables :
Concevoir un schéma documentaire et manipuler une collection.
Obligatoire ConsulterÉvaluer les requêtes, agrégations, indexations et transactions.
Obligatoire ConsulterDévelopper une API documentaire avec données de démonstration.
Livrables :
Concevoir un schéma documentaire et manipuler une collection.
Obligatoire ConsulterÉvaluer les requêtes, agrégations, indexations et transactions.
Obligatoire ConsulterDévelopper une API documentaire avec données de démonstration.
Livrables :
Concevoir un schéma documentaire et manipuler une collection.
Obligatoire ConsulterÉvaluer les requêtes, agrégations, indexations et transactions.
Obligatoire ConsulterDévelopper une API documentaire avec données de démonstration.
Livrables :
Concevoir un schéma documentaire et manipuler une collection.
Obligatoire ConsulterÉvaluer les requêtes, agrégations, indexations et transactions.
Obligatoire ConsulterDévelopper une API documentaire avec données de démonstration.
Livrables :
Ce cours s'adresse aux :
À l'issue de cette formation, vous serez capable de :
Réparties sur plusiers séquences
Solution cloud complète avec interface de gestion, API, data lake et synchronisation mobile.
Version auto-hébergée avec outils de gestion, surveillance et sauvegarde.
Applications et bibliothèques pour interagir avec MongoDB (Compass, Shell, Drivers).
MongoDB est une base de données NoSQL orientée documents, classée parmi les bases de données les plus populaires au monde. Contrairement aux bases de données relationnelles traditionnelles, MongoDB stocke les données sous forme de documents flexibles et évolutifs, ce qui en fait un choix idéal pour les applications modernes.
Stockage des données en format BSON (binaire JSON) pour une grande flexibilité
Distribution des données via le sharding pour gérer de grandes charges
Indexation avancée et accès mémoire pour des temps de réponse rapides
Chiffrement, authentification et RBAC (contrôle d'accès basé sur les rôles)
Stockage flexible pour les données utilisateur et le contenu des applications mobiles avec synchronisation hors ligne.
Gestion de catalogues produits complexes avec des attributs variables selon les catégories.
Analyse de données massives avec des agrégations puissantes et des pipelines de traitement.
Gestion des profils utilisateurs, des publications et des interactions sociales avec des schémas évolutifs.
Service cloud entièrement géré pour MongoDB, offrant évolutivité et haute disponibilité.
Interface graphique officielle pour explorer et analyser vos données MongoDB.
Interface en ligne de commande (CLI) interactive pour administrer et interroger MongoDB.
Plateforme de développement d'applications avec synchronisation des données en temps réel.
Contrairement aux bases de données relationnelles qui utilisent des tables et des lignes, MongoDB stocke les données sous forme de documents au format BSON (binaire JSON).
{
"_id": ObjectId("5f8d8d8d8d8d8d8d8d8d8d8d"),
"titre": "Le Seigneur des Anneaux",
"annee": 2001,
"duree": 178,
"genres": ["Aventure", "Fantasy", "Action"],
"realisateur": {
"nom": "Jackson",
"prenom": "Peter"
},
"acteurs": ["Elijah Wood", "Ian McKellen", "Viggo Mortensen"],
"pays": "Nouvelle-Zélande",
"note_imdb": 8.8
}
MongoDB est conçu pour être hautement évolutif et disponible. Voici ses composants clés :
Unité de base des données, stockée en format BSON (binaire JSON). Peut contenir des tableaux et des documents imbriqués.
Groupe de documents, équivalent à une table dans les bases relationnelles. Pas de schéma imposé.
Conteneur pour les collections, avec son propre ensemble de fichiers sur le système de fichiers.
Le fichier mongod.conf permet de configurer le port, le répertoire de données, la sécurité, etc.
# Extrait minimal de mongod.conf
storage:
dbPath: /var/lib/mongodb
data:
bindIp: 127.0.0.1
net:
port: 27017
security:
authorization: enabled
# Démarrer
sudo systemctl start mongod
# Arrêter
sudo systemctl stop mongod
# Se connecter localement
mongosh
# Se connecter à une base distante
mongosh "mongodb+srv://<user>:<password>@cluster0.mongodb.net/test"
Pour des tests rapides, MongoDB Atlas propose une instance cloud gratuite, sans installation locale.
Quel est le port par défaut utilisé par MongoDB?
Paramètres principaux lors de la création d'un cluster :
Interface graphique pour explorer et gérer votre base de données
Ligne de commande pour interagir avec MongoDB
const { MongoClient } = require('mongodb');
const uri = "mongodb+srv://username:password@cluster0.mongodb.net";
const client = new MongoClient(uri);
const { MongoClient } = require('mongodb');
const uri = "mongodb+srv://username:password@cluster0.mongodb.net";
const client = new MongoClient(uri);
from pymongo import MongoClient
uri = "mongodb+srv://username:password@cluster0.mongodb.net"
client = MongoClient(uri)
MongoClient mongoClient = MongoClients.create(
"mongodb+srv://username:password@cluster0.mongodb.net"
);
val client = MongoClient(
"mongodb+srv://username:password@cluster0.mongodb.net"
)
Création d'un utilisateur avec les droits nécessaires
db.createUser({
user: "myapp",
pwd: "secure_password",
roles: [
{ role: "readWrite", db: "myapp" },
{ role: "dbAdmin", db: "myapp" }
]
});
Configuration des IP autorisées
# IP spécifique
192.168.1.100/32
# Plage d'IP
192.168.1.0/24
# IP dynamique (avec masque)
192.168.1.0/28
Configuration de l'authentification
Configuration de l'encryption
Le M0 est le plan gratuit qui offre :
Choisir la région la plus proche pour :
La réplication (replica set) assure :
Chaque node est une copie complète de la base de données
Interface de démonstration - L'interface réelle peut varier
Interface de démonstration - L'interface réelle peut varier
Paramètres principaux lors de la création d'un cluster :
Création d'un utilisateur avec les droits nécessaires
db.createUser({
user: "myapp",
pwd: "secure_password",
roles: [
{ role: "readWrite", db: "myapp" },
{ role: "dbAdmin", db: "myapp" }
]
});
Configuration des IP autorisées
# IP spécifique
192.168.1.100/32
# Plage d'IP
192.168.1.0/24
# IP dynamique (avec masque)
192.168.1.0/28
Configuration de l'authentification
Configuration de l'encryption
Configuration des IP autorisées
# IP spécifique
192.168.1.100/32
# Plage d'IP
192.168.1.0/24
# IP dynamique (avec masque)
192.168.1.0/28
Configuration de l'authentification
Configuration de l'encryption
L'interface graphique officielle de MongoDB
L'interface en ligne de commande de MongoDB
mongosh "mongodb+srv://cluster0.mongodb.net" --username yourUsername
Exemples de connexions pour différents langages
const { MongoClient } = require('mongodb');
const uri = "mongodb+srv://username:password@cluster0.mongodb.net";
const client = new MongoClient(uri);
from pymongo import MongoClient
client = MongoClient("mongodb+srv://username:password@cluster0.mongodb.net")
MongoClient mongoClient = MongoClients.create(
"mongodb+srv://username:password@cluster0.mongodb.net");
import com.mongodb.client.MongoClients
import org.mongodb.scala.MongoClient
// Connexion avec le driver Scala
val uri = "mongodb+srv://username:password@cluster0.mongodb.net"
val mongoClient = MongoClient(uri)
// Utilisation avec le driver Java
val javaClient = MongoClients.create(uri)
// Exemple de requête
val database = mongoClient.getDatabase("mydb")
val collection = database.getCollection("mycollection")
// Insertion d'un document
val document = Document("name" -> "John", "age" -> 30)
collection.insertOne(document).subscribe(
(result: InsertOneResult) => println(s"Document inserted: ${result.getInsertedId}")
)
Configuration minimale recommandée :
MongoDB est une base de données NoSQL orientée document, conçue pour la flexibilité, la scalabilité horizontale et les performances élevées.
Une collection dans MongoDB est un groupe de documents, équivalent à une table dans les bases de données relationnelles. Cependant, contrairement aux tables, les collections n'imposent pas de schéma strict.
users, orders).
Figure 1 : Architecture de MongoDB montrant les relations entre les différents composants.
Moteur de stockage haute performance avec :
Un site e-commerce utilisant MongoDB peut gérer jusqu'à 100 000 lectures par seconde avec des temps de réponse inférieurs à 10ms, ce qui permet une expérience utilisateur fluide même pendant les périodes de pointe comme le Black Friday.
Architecture distribuée conçue pour :
Une application de médias sociaux peut commencer avec un seul serveur MongoDB. À mesure que le nombre d'utilisateurs passe de 1 000 à 10 millions, l'application peut évoluer en ajoutant des shards (partitions de données) sur plusieurs serveurs, sans temps d'arrêt.
Avantages du schéma dynamique :
Dans une application de blog, vous pourriez initialement stocker uniquement le titre et le contenu d'un article. Plus tard, vous pourriez ajouter des champs comme des tags, une image de couverture ou des commentaires directement dans le même document, sans avoir à modifier la structure de la base de données.
```
// Premier enregistrement
{
titre: "Mon premier article",
contenu: "Contenu de l'article...",
date: ISODate("2023-01-01")
}
// Plus tard, ajout de nouveaux champs sans modification de schéma
{
titre: "Nouvel article",
contenu: "Contenu mis à jour...",
date: ISODate("2023-04-15"),
tags: ["technologie", "programmation"],
image: "url-de-l-image.jpg",
auteur: {
nom: "Alice",
role: "rédacteur"
},
commentaires: [
{ auteur: "Bob", texte: "Super article !", date: ISODate("2023-04-16") }
]
}
```
Une large gamme d'outils :
Astuce : Ces outils rendent MongoDB accessible aussi bien aux développeurs qu'aux analystes de données, facilitant ainsi la collaboration entre les équipes.
Stockage de documents JSON/BSON
Ex: MongoDB, CouchDB
Stockage simple clé-valeur
Ex: Redis, DynamoDB
Stockage par colonnes
Ex: Cassandra, HBase
Relations complexes entre données
Ex: Neo4j, ArangoDB
| ACID (SQL) | BASE (NoSQL) | Description |
|---|---|---|
| Atomicité | Disponibilité de base | Disponibilité même en cas de pannes |
| Cohérence | État souple (Soft state) | Les données peuvent évoluer sans mise à jour |
| Isolation | Cohérence à terme | Les données finissent par être cohérentes |
| Durabilité | Scalabilité horizontale | Capacité à gérer de grandes quantités de données |
MongoDB excelle dans les cas d'utilisation nécessitant flexibilité et évolutivité. Pour les systèmes transactionnels complexes, envisagez une base de données relationnelle traditionnelle.
Les opérations CRUD (Create, Read, Update, Delete) sont fondamentales pour interagir avec une base de données MongoDB. Voici comment les mettre en œuvre :
Pour insérer des documents dans une collection :
// Insérer un seul document
db.collection('users').insertOne({
name: 'Jean Dupont',
email: 'jean@exemple.com',
age: 30,
status: 'actif'
});
// Insérer plusieurs documents
db.collection('posts').insertMany([
{ title: 'Premier article', content: 'Contenu...', likes: 0 },
{ title: 'Deuxième article', content: 'Contenu...', tags: ['tech', 'mongodb'] }
]);
_id unique pour chaque document si aucun n'est spécifié.
Pour rechercher des documents :
// Trouver tous les documents
db.collection('users').find({});
// Avec des critères de recherche
db.collection('users').find({ status: 'actif' });
// Avec projection (sélection des champs)
db.collection('users').find(
{ age: { $gt: 25 } },
{ projection: { name: 1, email: 1, _id: 0 } }
);
// Trier et limiter les résultats
db.collection('posts')
.find({})
.sort({ created_at: -1 })
.limit(10);
Pour mettre à jour des documents :
// Mettre à jour un seul document
db.collection('users').updateOne(
{ email: 'jean@exemple.com' },
{ $set: { status: 'inactif' } }
);
// Mettre à jour plusieurs documents
db.collection('posts').updateMany(
{ views: { $lt: 100 } },
{ $inc: { views: 1 } }
);
// Opérateurs de mise à jour courants :
// $set, $unset, $inc, $push, $pull, $addToSet
Pour supprimer des documents :
// Supprimer un seul document
db.collection('users').deleteOne({ email: 'jean@exemple.com' });
// Supprimer plusieurs documents
db.collection('posts').deleteMany({ status: 'archived' });
// Attention : Sans filtre, cela supprime tous les documents de la collection !
// db.collection('users').deleteMany({});
insertMany, updateMany) pour améliorer les performancesMongoDB utilise le format BSON (Binary JSON) pour stocker les documents. C'est une représentation binaire de JSON avec des types de données supplémentaires.
Avantages du BSON :
Un document MongoDB typique :
{
_id: ObjectId("507f1f77bcf86cd799439011"),
nom: "Jean Dupont",
age: 30,
email: "jean.dupont@example.com",
adresse: {
rue: "123 Rue Exemple",
ville: "Paris",
codePostal: "75000"
},
competences: ["MongoDB", "JavaScript", "Node.js"],
dateInscription: ISODate("2023-01-15T10:30:00Z")
}
Regrouper les données fréquemment accédées ensemble
Privilégier l'imbrication quand c'est pertinent
Pour les relations un-à-plusieurs ou plusieurs-à-plusieurs
Éviter les documents trop volumineux (>16Mo)
// Syntaxe de base de la méthode find()
// db.collection.find(query, projection)
// Exemple 1: Trouver tous les documents
const allDocuments = db.users.find({});
// Exemple 2: Trouver avec des critères de recherche
const activeUsers = db.users.find({
status: 'active',
lastLogin: { $gt: new Date('2023-01-01') }
});
// Exemple 3: Utilisation de la projection
const userNames = db.users.find(
{ role: 'user' },
{
name: 1,
email: 1,
_id: 0 // Exclure le champ _id
}
);
// Exemple 4: Trier et limiter les résultats
const recentOrders = db.orders
.find({ status: 'completed' })
.sort({ orderDate: -1 })
.limit(10);
// Exemple 5: Compter les documents
const activeUserCount = db.users.countDocuments({ status: 'active' });
// Exemple 6: Utilisation d'opérateurs de requête
const highValueOrders = db.orders.find({
total: { $gt: 1000 }, // Montant supérieur à 1000
status: { $in: ['pending', 'processing'] }, // Statut dans la liste
orderDate: {
$gte: new Date('2023-01-01'),
$lt: new Date('2024-01-01')
}
});
// Exemple 7: Recherche avec expression régulière
const nameStartsWithJ = db.users.find({
name: { $regex: /^J/i } // Noms commençant par J (insensible à la casse)
});
// Exemple 8: Requête sur des tableaux
const usersWithSpecificTags = db.users.find({
tags: { $all: ['premium', 'verified'] } // Doit avoir tous les tags spécifiés
});
// Exemple 9: Requête avec opérateurs logiques
const complexQuery = db.products.find({
$or: [
{ category: 'electronics', price: { $lt: 500 } },
{ category: 'books', rating: { $gte: 4 } }
],
inStock: true
});
// Exemple 10: Utilisation de $elemMatch pour les tableaux d'objets
const usersWithSpecificAddress = db.users.find({
addresses: {
$elemMatch: {
type: 'billing',
city: 'Paris'
}
}
});
// Trouver tous les utilisateurs actifs
db.users.find({
status: 'active',
lastLogin: { $gt: new Date('2023-01-01') }
}).sort({ createdAt: -1 });
// Sélectionner uniquement certains champs
db.users.find(
{ role: 'customer' },
{
name: 1,
email: 1,
_id: 0 // Exclure le champ _id
}
).limit(10);
| Opérateur | Description | Exemple |
|---|---|---|
$eq |
Égal à | { age: { $eq: 25 } } |
$gt, $gte |
Plus grand (ou égal) que | { age: { $gt: 21 } } |
$in, $nin |
Dans / pas dans un tableau | { role: { $in: ["admin", "editor"] } } |
$and, $or |
Opérateurs logiques | { $or: [ { status: "A" }, { qty: { $lt: 30 } } ] } |
.explain() pour analyser les performances des requêtes// Insérer un seul document
const result = await db.users.insertOne({
name: "Jean Dupont",
email: "jean@example.com",
age: 30,
roles: ["user", "admin"],
createdAt: new Date()
});
console.log(`Document inséré avec l'ID: ${result.insertedId}`);
// Résultat attendu :
// Document inséré avec l'ID: 5f8d... (ObjectId)
// Insérer plusieurs documents
const result = await db.products.insertMany([
{
name: "Ordinateur portable",
category: "Électronique",
price: 999.99,
inStock: true,
tags: ["nouveau", "promo"]
},
{
name: "Souris sans fil",
category: "Périphériques",
price: 49.99,
inStock: true
},
{
name: "Clavier mécanique",
category: "Périphériques",
price: 89.99,
inStock: false
}
], {
writeConcern: { w: "majority" },
ordered: true // Annule l'insertion en cas d'erreur
});
console.log(`${result.insertedCount} documents insérés`);
console.log("IDs des documents insérés:", result.insertedIds);
// Résultat attendu :
// 3 documents insérés
// IDs des documents insérés: {
// '0': ObjectId("..."),
// '1': ObjectId("..."),
// '2': ObjectId("...")
// }
| Option | Type | Description | Valeur par défaut |
|---|---|---|---|
writeConcern |
Document | Niveau de garantie d'écriture | { w: 1 } |
ordered |
Boolean | Arrêter à la première erreur si false | true |
bypassDocumentValidation |
Boolean | Contourner la validation du schéma | false |
insertMany() pour insérer plusieurs documents en une seule opérationordered pour ignorer les erreurs et continuer l'insertionSi non spécifié, MongoDB génère un _id unique de type ObjectId :
{
_id: ObjectId("507f1f77bcf86cd799439011"), // Format 12-byte
// 4 bytes: timestamp
// 5 bytes: random value
// 3 bytes: counter
...
}
Pour utiliser un identifiant personnalisé :
// Insérer un seul document
const result = await db.users.insertOne({
name: "Jean Dupont",
email: "jean@example.com",
age: 30,
roles: ["user", "admin"],
createdAt: new Date()
});
console.log(`Document inséré avec l'ID: ${result.insertedId}`);
// Résultat attendu :
// Document inséré avec l'ID: 5f8d... (ObjectId)
// Mettre à jour un document spécifique
const result = await db.products.updateOne(
{ _id: ObjectId("507f1f77bcf86cd799439011") }, // Filtre
{
$set: { // Opérateur de mise à jour
price: 1099.99,
lastModified: new Date()
},
$inc: { viewCount: 1 },
$addToSet: { tags: "nouveau" }
},
{
upsert: false, // Ne pas créer le document s'il n'existe pas
writeConcern: { w: "majority" }
}
);
console.log(`${result.matchedCount} document(s) correspondant(s)`);
console.log(`${result.modifiedCount} document(s) modifié(s)`);
console.log(`ID du document inséré: ${result.upsertedId || 'Aucun'}`);
// Résultat attendu :
// 1 document(s) correspondant(s)
// 1 document(s) modifié(s)
// ID du document inséré: Aucun
// Mettre à jour plusieurs documents correspondant aux critères
const result = await db.products.updateMany(
{
category: "Électronique",
price: { $lt: 1000 } // Produits électroniques à moins de 1000€
},
{
$set: {
onSale: true,
discount: 0.1, // 10% de réduction
lastPromoUpdate: new Date()
},
$inc: { price: 50 } // Augmenter le prix de 50€
},
{
writeConcern: { w: "majority" },
upsert: false
}
);
console.log(`${result.matchedCount} document(s) correspondant(s)`);
console.log(`${result.modifiedCount} document(s) modifié(s)`);
console.log(`ID du document inséré: ${result.upsertedId || 'Aucun'}`);
// Résultat attendu (exemple) :
// 15 document(s) correspondant(s)
// 15 document(s) modifié(s)
// ID du document inséré: Aucun
$set : Définit la valeur d'un champ$unset : Supprime un champ$rename : Renomme un champ$inc : Incrémente une valeur numérique$mul : Multiplie une valeur numérique$min/$max : Met à jour si la valeur est plus petite/plus grande$push : Ajoute un élément à un tableau$addToSet : Ajoute si non présent$pop : Supprime le premier/dernier élément$pull : Supprime les éléments correspondants$pullAll : Supprime plusieurs valeurs$each : Utilisé avec $push et $addToSet pour ajouter plusieurs éléments
// Mettre à jour un profil utilisateur complexe
await db.users.updateOne(
{ _id: userId },
{
$set: {
"profile.lastUpdated": new Date(),
"contact.email": "new.email@example.com",
"settings.theme": "dark"
},
$inc: { "stats.profileViews": 1 },
$addToSet: {
tags: { $each: ["premium", "verified"] }
},
$pull: {
notifications: {
type: "promo",
status: "unread"
}
}
},
{
upsert: true, // Crée le document s'il n'existe pas
writeConcern: { w: "majority" }
}
);
_id dans le filtrePermet des mises à jour complexes en utilisant le pipeline d'agrégation :
// Mettre à jour en fonction des valeurs existantes
await db.orders.updateMany
(
{ status: "processing" },
[
{
$set: {
lastUpdated: "$$NOW",
total: {
$add: [
"$subtotal",
{ $multiply: ["$subtotal", "$taxRate"] },
"$shipping"
]
}
}
},
{
$unset: ["tempField1", "tempField2"]
}
]
);
// Supprimer un document spécifique
const result = await db.users.deleteOne(
{ _id: ObjectId("507f1f77bcf86cd799439011") }, // Filtre
{
writeConcern: { w: "majority" },
collation: { locale: "fr", strength: 1 } // Optionnel : pour la sensibilité à la casse
}
);
console.log(`${result.deletedCount} document(s) supprimé(s)`);
// Exemple avec journalisation avant suppression
try {
const user = await db.users.findOne({ _id: ObjectId("507f1f77bcf86cd799439011") });
if (user) {
await db.deletedUsers.insertOne({
...user,
deletedAt: new Date(),
deletedBy: "admin@example.com"
});
const result = await db.users.deleteOne({ _id: user._id });
console.log(`Utilisateur ${user.email} supprimé avec succès`);
}
} catch (error) {
console.error("Erreur lors de la suppression:", error);
}
// Résultat attendu (exemple) :
// 1 document(s) supprimé(s)
// OU
// Utilisateur test@example.com supprimé avec succès
// Supprimer plusieurs documents correspondant aux critères
const result = await db.logs.deleteMany(
{
// Supprimer les logs plus anciens que 30 jours
timestamp: {
$lt: new Date(new Date() - 30 * 24 * 60 * 60 * 1000)
},
// Ne pas supprimer les logs importants
priority: { $ne: "high" }
},
{
writeConcern: {
w: "majority",
wtimeout: 5000 // Timeout de 5 secondes
},
comment: "Nettoyage des logs mensuel" // Pour le suivi des opérations
}
);
console.log(`${result.deletedCount} logs supprimés`);
// Exemple avec journalisation avancée
const batchSize = 1000;
let deletedCount = 0;
let lastId = null;
while (true) {
// Récupérer un lot de documents à supprimer
const batch = await db.logs
.find(lastId ? {
_id: { $gt: lastId },
timestamp: { $lt: new Date(new Date() - 30 * 24 * 60 * 60 * 1000) }
} : {
timestamp: { $lt: new Date(new Date() - 30 * 24 * 60 * 60 * 1000) }
})
.sort({ _id: 1 })
.limit(batchSize)
.toArray();
if (batch.length === 0) break;
// Récupérer les IDs à supprimer
const idsToDelete = batch.map(doc => doc._id);
// Journaliser avant suppression
await db.deletedLogs.insertMany(batch.map(doc => ({
...doc,
deletedAt: new Date(),
deletedBy: "cleanup-script"
})));
// Supprimer le lot
const result = await db.logs.deleteMany({ _id: { $in: idsToDelete } });
deletedCount += result.deletedCount;
// Mettre à jour le dernier ID traité
lastId = batch[batch.length - 1]._id;
console.log(`Lot de ${result.deletedCount} logs supprimés (total: ${deletedCount})`);
// Pause pour réduire la charge sur le serveur
await new Promise(resolve => setTimeout(resolve, 100));
}
console.log(`Opération terminée. Total supprimé: ${deletedCount} logs.`);
// Résultat attendu (exemple) :
// Lot de 1000 logs supprimés (total: 1000)
// Lot de 1000 logs supprimés (total: 2000)
// Lot de 345 logs supprimés (total: 2345)
// Opération terminée. Total supprimé: 2345 logs.
Récupérer les commandes avec les détails des produits et les informations clients, en calculant le total par catégorie.
db.orders.aggregate([
// Étape 1: Filtrer les commandes des 30 derniers jours
{
$match: {
orderDate: { $gte: new Date(new Date() - 30 * 24 * 60 * 60 * 1000) }
}
},
// Étape 2: Joindre avec la collection des clients
{
$lookup: {
from: "customers",
localField: "customerId",
foreignField: "_id",
as: "customer"
}
},
// Étape 3: Déplier le tableau des articles commandés
{ $unwind: "$items" },
// Étape 4: Joindre avec la collection des produits
{
$lookup: {
from: "products",
localField: "items.productId",
foreignField: "_id",
as: "product"
}
},
// Étape 5: Déplier le tableau des produits
{ $unwind: "$product" },
// Étape 6: Calculer le total pour chaque ligne de commande
{
$addFields: {
"items.total": { $multiply: ["$items.quantity", "$product.price"] }
}
},
// Étape 7: Grouper par catégorie de produit et calculer les totaux
{
$group: {
_id: { category: "$product.category" },
totalSales: { $sum: "$items.total" },
orderCount: { $sum: 1 },
averageOrderValue: { $avg: "$items.total" }
}
},
// Étape 8: Trier par total des ventes (décroissant)
{ $sort: { totalSales: -1 } }
])
Trouver les 10 restaurants les plus proches dans un rayon de 2 km, avec une note moyenne supérieure à 4.
// 1. Création d'un index géospatial 2dsphere (à exécuter une seule fois)
// db.restaurants.createIndex({ location: "2dsphere" });
// 2. Requête pour trouver les restaurants à proximité
const pointInteret = {
type: "Point",
coordinates: [2.3522, 48.8566] // Paris, France
};
const result = await db.restaurants.aggregate([
{
$geoNear: {
near: pointInteret,
distanceField: "distance",
maxDistance: 2000, // 2 km en mètres
spherical: true,
query: {
'grades.score': { $gte: 4 },
cuisine: { $exists: true }
}
}
},
{
$lookup: {
from: "neighborhoods",
localField: "neighborhood",
foreignField: "name",
as: "neighborhood_info"
}
},
{ $unwind: "$neighborhood_info" },
{
$project: {
name: 1,
cuisine: 1,
"address.street": 1,
distance: { $round: ["$distance", 0] },
neighborhood: "$neighborhood_info.name",
borough: 1,
lastGrade: { $arrayElemAt: ["$grades", -1] }
}
},
{ $sort: { distance: 1 } },
{ $limit: 10 }
]);
console.log(JSON.stringify(result, null, 2));
Recherche avancée d'articles de blog avec pondération des champs, filtrage par date, catégorie et popularité.
// 1. Création d'un index de recherche en texte (à exécuter une seule fois)
// db.articles.createIndex(
// {
// title: "text",
// content: "text",
// tags: "text"
// },
// {
// weights: {
// title: 5, // Le titre a plus de poids
// tags: 3, // Les tags ont un poids moyen
// content: 1 // Le contenu a le poids le plus faible
// },
// name: "text_search_index"
// }
// );
// 2. Requête de recherche avancée avec agrégation
const searchTerm = "développement web";
const minDate = new Date(new Date().setFullYear(new Date().getFullYear() - 1)); // Dernière année
const result = await db.articles.aggregate([
{
$search: {
text: {
query: searchTerm,
path: ["title", "content", "tags"],
fuzzy: {
maxEdits: 2, // Tolère jusqu'à 2 fautes de frappe
prefixLength: 3, // Nécessite les 3 premières lettres exactes
maxExpansions: 100 // Limite l'expansion des termes
},
score: {
// Boost pour les correspondances exactes
boost: { value: 2 }
}
},
// Filtres supplémentaires
compound: {
filter: [
{
range: {
path: "publishedAt",
gte: minDate,
lte: new Date()
}
},
{
range: {
path: "readTime",
lte: 15 // Temps de lecture max de 15 minutes
}
},
{
text: {
query: ["tutoriel", "guide", "exemple"],
path: "tags"
}
}
],
// Boost pour les articles populaires
should: [
{
range: {
path: "views",
boost: {
linear: {
origin: 0,
scale: 10000,
decay: 0.5
}
}
}
},
{
range: {
path: "claps",
boost: {
linear: {
origin: 0,
scale: 1000,
decay: 0.5
}
}
}
}
]
}
}
},
// Jointure avec la collection des auteurs
{
$lookup: {
from: "users",
localField: "authorId",
foreignField: "_id",
as: "author"
}
},
{ $unwind: "$author" },
// Projection des champs pertinents
{
$project: {
_id: 1,
title: 1,
excerpt: 1,
readTime: 1,
publishedAt: 1,
views: 1,
claps: 1,
tags: 1,
author: {
name: 1,
avatar: 1,
title: 1
},
// Calcul du score de pertinence
relevance: {
$meta: "searchScore"
},
// Calcul d'un score personnalisé
score: {
$add: [
{ $multiply: [{ $meta: "searchScore" }, 0.6] },
{ $multiply: [{ $divide: ["$views", 1000] }, 0.2] },
{ $multiply: [{ $divide: ["$claps", 100] }, 0.2] }
]
}
}
},
// Tri par score personnalisé
{ $sort: { score: -1 } },
// Pagination
{ $skip: 0 },
{ $limit: 10 }
]);
console.log(JSON.stringify(result, null, 2));
Analyser les ventes par période (jour, semaine, mois) avec des fenêtres glissantes.
// 1. Création d'une collection de séries temporelles (à exécuter une seule fois)
// db.createCollection("sensorReadings", {
// timeseries: {
// timeField: "timestamp",
// metaField: "sensorId",
// granularity: "minutes"
// }
// });
// 2. Agrégation avancée sur les séries temporelles
const startDate = new Date();
startDate.setMonth(startDate.getMonth() - 6); // Données des 6 derniers mois
const result = await db.sensorReadings.aggregate([
// Étape 1: Filtrer par plage de dates
{
$match: {
timestamp: { $gte: startDate },
status: "active"
}
},
// Étape 2: Grouper par fenêtres de temps et capteur
{
$group: {
_id: {
// Arrondir à l'heure la plus proche
date: {
$dateTrunc: {
date: "$timestamp",
unit: "hour",
binSize: 1
}
},
sensorId: "$sensorId",
location: "$location"
},
// Calculer les métriques
avgValue: { $avg: "$value" },
maxValue: { $max: "$value" },
minValue: { $min: "$value" },
sampleCount: { $sum: 1 },
// Détecter les anomalies (valeurs en dehors de 2 écarts-types)
stdDev: { $stdDevSamp: "$value" },
// Garder le premier et dernier timestamp de la fenêtre
firstTimestamp: { $first: "$timestamp" },
lastTimestamp: { $last: "$timestamp" },
// Collecter les 5 premières valeurs pour référence
sampleValues: { $push: { $slice: ["$value", 5] } }
}
},
// Étape 3: Calculer les anomalies
{
$addFields: {
isAnomaly: {
$or: [
{
$gt: [
"$maxValue",
{ $add: ["$avgValue", { $multiply: [2, "$stdDev"] }] }
]
},
{
$lt: [
"$minValue",
{ $subtract: ["$avgValue", { $multiply: [2, "$stdDev"] }] }
]
}
]
},
// Calculer la tendance sur la fenêtre
valueChange: {
$subtract: [
{ $arrayElemAt: ["$sampleValues", -1] },
{ $arrayElemAt: ["$sampleValues", 0] }
]
}
}
},
// Étape 4: Projeter les champs pertinents
{
$project: {
_id: 0,
timestamp: "$_id.date",
sensorId: "$_id.sensorId",
location: "$_id.location",
metrics: {
average: { $round: ["$avgValue", 2] },
max: { $round: ["$maxValue", 2] },
min: { $round: ["$minValue", 2] },
sampleCount: 1,
standardDeviation: { $round: ["$stdDev", 2] },
isAnomaly: 1,
valueChange: { $round: ["$valueChange", 2] },
timeRange: {
start: "$firstTimestamp",
end: "$lastTimestamp"
}
}
}
},
// Étape 5: Trier par date et capteur
{
$sort: {
timestamp: 1,
sensorId: 1
}
},
// Étape 6: Optionnel - Fenêtres mobiles
{
$setWindowFields: {
partitionBy: "$sensorId",
sortBy: { timestamp: 1 },
output: {
movingAvg: {
$avg: "$metrics.average",
window: {
documents: ["unbounded", "current"]
}
},
movingStdDev: {
$stdDevSamp: "$metrics.average",
window: {
documents: ["unbounded", "current"]
}
}
}
}
}
]);
console.log(JSON.stringify(result, null, 2));
// 1. Création d'un index simple sur un champ unique
// Crée un index croissant (1) sur le champ 'email'
db.utilisateurs.createIndex({ email: 1 });
// 2. Création d'un index composé sur plusieurs champs
db.commandes.createIndex({ clientId: 1, date: -1 });
// - clientId en ordre croissant
// - date en ordre décroissant (pour avoir les commandes les plus récentes en premier)
// 3. Création d'un index unique avec contrainte
db.utilisateurs.createIndex(
{ username: 1 },
{ unique: true, name: "username_unique" }
);
// 4. Création d'un index TTL (Time-To-Live) pour l'expiration automatique des documents
db.sessions.createIndex(
{ lastActivity: 1 },
{ expireAfterSeconds: 3600 * 24 * 7 } // Supprime après 7 jours d'inactivité
);
// 5. Création d'un index de texte pour la recherche plein texte
db.articles.createIndex(
{ titre: "text", contenu: "text" },
{ weights: { titre: 3, contenu: 1 } } // Le titre a plus de poids que le contenu
);
// 6. Création d'un index géospatial 2dsphere pour les requêtes géographiques
db.restaurants.createIndex({ localisation: "2dsphere" });
// 7. Création d'un index partiel (seulement sur les documents qui correspondent au filtre)
db.articles.createIndex(
{ vues: 1 },
{ partialFilterExpression: { etat: "publié" } }
);
// 8. Création d'un index avec options avancées
db.produits.createIndex(
{ nom: 1, categorie: 1 },
{
name: "idx_nom_categorie",
background: true, // Construction en arrière-plan
sparse: true, // N'inclut que les documents où le champ existe
collation: { // Règles de tri spécifiques
locale: "fr",
strength: 2
}
}
);
// Vérification des index existants sur une collection
db.utilisateurs.getIndexes();
// Suppression d'un index
db.utilisateurs.dropIndex("email_1");
// Suppression de tous les index (sauf _id)
// db.utilisateurs.dropIndexes();
$match : Filtrage des documents$group : Agrégation de données$sort : Tri des résultats$project : Sélection des champs$limit : Limite des résultatsdb.collection.aggregate([
{ $match: { age: { $gt: 25 } } },
{ $group: {
_id: "$city",
averageAge: { $avg: "$age" }
}
},
{ $sort: { averageAge: -1 } },
{ $limit: 5 }
]);
$match (filtrage), $group (agrégation), $project (projection de champs)$sort, $limit, $unwind, $lookup (jointure)db.commandes.aggregate([
{ $match: { statut: "livrée" } },
{ $group: { _id: "$client", total: { $sum: "$montant" } } },
{ $sort: { total: -1 } }
]);
$explain pour analyser les plans d’exécutionconst session = db.getMongo().startSession();
session.startTransaction();
try {
db.comptes.updateOne({ _id: 1 }, { $inc: { solde: -100 } });
db.comptes.updateOne({ _id: 2 }, { $inc: { solde: 100 } });
session.commitTransaction();
} catch (e) {
session.abortTransaction();
}
mongoimport --db test --collection tweets --file tweets.json --jsonArraydb.tweets.aggregate([
{ $group: { _id: "$user", nb: { $sum: 1 } } },
{ $sort: { nb: -1 } }
]);
// Syntaxe de base de find()
db.collection.find(
query, // Critères de sélection (optionnel)
{ // Projection (optionnel)
field1: 1, // Inclure le champ (1 ou true)
field2: 0, // Exclure le champ (0 ou false)
// ...
}
).options(); // Options de requête
| Paramètre | Type | Description | Valeur par défaut |
|---|---|---|---|
query |
Document | Critères de sélection (opérateurs de requête) | {} (tous les documents) |
projection |
Document | Champs à inclure/exclure (1/0 ou true/false) | Tous les champs |
.limit(n) : Limite le nombre de résultats.skip(n) : Saute les n premiers documents.sort({field: 1/-1}) : Trie les résultats.project({}) : Alternative à la projection dans find()// Trouver tous les documents dans une collection
const allUsers = await db.users.find({}).toArray();
console.log(`Nombre total d'utilisateurs: ${allUsers.length}`);
// Trouver avec des critères de recherche
const activeUsers = await db.users.find({
status: "active",
lastLogin: { $gt: new Date(new Date() - 30 * 24 * 60 * 60 * 1000) }
}).toArray();
console.log(`Utilisateurs actifs ce mois-ci: ${activeUsers.length}`);
// Utilisation de la projection pour ne récupérer que certains champs
const userEmails = await db.users.find(
{ role: "admin" },
{
projection: {
email: 1,
name: 1,
_id: 0 // Exclure l'ID par défaut
}
}
).toArray();
console.log("Emails des administrateurs:", userEmails);
// Trier et limiter les résultats
const recentOrders = await db.orders
.find({ status: "completed" })
.sort({ orderDate: -1 }) // -1 pour décroissant, 1 pour croissant
.limit(10) // Seulement les 10 premiers résultats
.toArray();
console.log("10 commandes récentes:", recentOrders);
// Pagination avec skip et limit
const page = 2;
const perPage = 20;
const products = await db.products
.find({ category: "electronics" })
.sort({ price: 1 })
.skip((page - 1) * perPage)
.limit(perPage)
.toArray();
console.log(`Page ${page} des produits électroniques:`, products);
// Compter les documents sans les récupérer
const inactiveUserCount = await db.users.countDocuments({
status: "inactive"
});
console.log(`Nombre d'utilisateurs inactifs: ${inactiveUserCount}`);
// Utilisation de l'opérateur $in pour plusieurs valeurs
const featuredCategories = ["Électronique", "Informatique", "Téléphonie"];
const featuredProducts = await db.products
.find({
category: { $in: featuredCategories },
stock: { $gt: 0 }
})
.toArray();
console.log(`Produits en vedette en stock: ${featuredProducts.length}`);
// Recherche de texte
const searchResults = await db.articles
.find({
$text: { $search: "MongoDB introduction" },
status: "published"
})
.sort({ score: { $meta: "textScore" } })
.toArray();
console.log(`Résultats de la recherche: ${searchResults.length} articles trouvés`);
$eq : Égal à$ne : Différent de$gt, $gte : Plus grand (ou égal) que$lt, $lte : Plus petit (ou égal) que$in, $nin : Dans / pas dans un tableau$and, $or, $nor : Opérateurs logiques$exists : Champ existant$regex : Expression régulière$elemMatch : Correspondance dans un tableauLa méthode findOne() est similaire à find() mais retourne uniquement le premier document correspondant aux critères de recherche, ou null si aucun document n'est trouvé.
toArray() ou next()null si aucun document n'est trouvé (au lieu d'un curseur vide)// Trouver un utilisateur par son email
const user = await db.users.findOne({
email: "jean.dupont@example.com"
});
if (user) {
console.log(`Utilisateur trouvé: ${user.name}`);
} else {
console.log("Aucun utilisateur trouvé avec cet email");
}
// Utilisation avec projection pour ne récupérer que certains champs
const userProfile = await db.users.findOne(
{ username: "johndoe" },
{
projection: {
name: 1,
email: 1,
lastLogin: 1,
_id: 0
}
}
);
console.log("Profil utilisateur:", userProfile);
// Trouver le document avec le plus grand score
const topScore = await db.scores.findOne(
{},
{
sort: { score: -1 },
projection: { player: 1, score: 1, _id: 0 }
}
);
console.log("Meilleur score:", topScore);
// Utilisation avec des opérateurs de requête
const recentOrder = await db.orders.findOne({
customerId: "user123",
status: { $in: ["processing", "shipped"] },
orderDate: {
$gte: new Date(new Date() - 7 * 24 * 60 * 60 * 1000)
}
}, {
sort: { orderDate: -1 },
projection: {
orderId: 1,
total: 1,
status: 1,
items: 1
}
});
if (recentOrder) {
console.log("Dernière commande récente:", recentOrder);
}
// Recherche avec un index texte
const article = await db.articles.findOne(
{
$text: { $search: "MongoDB performance" },
status: "published"
},
{
sort: { score: { $meta: "textScore" } },
projection: {
title: 1,
excerpt: 1,
score: { $meta: "textScore" },
_id: 0
}
}
);
if (article) {
console.log("Article trouvé:", article.title);
console.log(`Score de pertinence: ${article.score.toFixed(2)}`);
}
// Utilisation avec des opérateurs de mise à jour pour une opération "trouver et mettre à jour"
const updatedUser = await db.users.findOneAndUpdate(
{ email: "jean.dupont@example.com" },
{ $inc: { loginCount: 1 }, $set: { lastLogin: new Date() } },
{
returnNewDocument: true, // Retourne le document après la mise à jour
projection: { password: 0 } // Exclure le mot de passe
}
);
if (updatedUser) {
console.log(`Bienvenue de nouveau, ${updatedUser.name}!`);
console.log(`Nombre de connexions: ${updatedUser.loginCount}`);
}
encryptionAtRestexplain() pour comprendre le plan d’exécution.mongodump et mongorestore pour exporter/importer des bases.# Ex : création d’un sharded cluster (simplifié)
sh.enableSharding("maDB")
sh.shardCollection("maDB.utilisateurs", { "_id": "hashed" })
# Ex : initialisation d’un Replica Set
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "mongo1:27017" },
{ _id: 1, host: "mongo2:27017" },
{ _id: 2, host: "mongo3:27017" }
]
})
db.utilisateurs.createIndex({ nom: 1, age: -1 })docker-compose up -dsh.status()mongoose ou mongodb.pymongo./utilisateurs, /produits, etc.GET (lecture), POST (création), PUT (mise à jour), DELETE (suppression)// GET tous les utilisateurs
app.get('/utilisateurs', async (req, res) => {
const users = await db.collection('utilisateurs').find().toArray();
res.json(users);
});
// POST un nouvel utilisateur
app.post('/utilisateurs', async (req, res) => {
const result = await db.collection('utilisateurs').insertOne(req.body);
res.json(result);
});
fetch, axios), Python (requests), Java, etc.query {
utilisateurs {
nom
age
email
}
}
produits, utilisateurs, commandesproduits et y insérer plusieurs documentsGET /produits qui retourne tous les produitsiot_datainteractions : stocke les clics, achats, notesConstruire un pipeline temps réel qui collecte, traite et stocke des données de navigation web (clickstream) :
db.clicks.find()createIndex, types d'index, compound indexes)
Publié le 25/09/2026