Cours
Base de données NoSQL populaire, MongoDB offre une gestion des données flexible et extensible. Ce guide est votre point de départ pour maîtriser son Query API intuitif, qui vous permet d’interagir avec vos données via un format BSON (Binary JSON) simple, optimisé pour l’efficacité et les types de données.
Dans cet article, nous verrons les opérations fondamentales create, read, update, delete (CRUD), les requêtes précises avec filtres et projection, la puissance des pipelines d’agrégation pour transformer les données, ainsi que l’indexation pour accélérer les performances. À la fin, vous aurez de solides bases pour interroger et manipuler efficacement les données de vos collections MongoDB.
Concepts fondamentaux : opérations CRUD
L’épine dorsale de toute interaction avec une base est CRUD : create, read, update et delete. Voyons comment chacune s’effectue dans MongoDB.
Créer des données (insert)
Pour ajouter de nouveaux documents à une collection, utilisez les méthodes insert. Les documents MongoDB sont des objets de type JSON.
insertOne()
Cette méthode ajoute un document unique à une collection.
// A sample document to insert
const newProduct = {
name: "Wireless Mouse",
brand: "Logitech",
price: 29.99,
inStock: true
};
// Insert the new document into the 'products' collection
db.products.insertOne(newProduct);
insertMany()
Cette méthode ajoute plusieurs documents en une seule fois, beaucoup plus efficace que des insertions unitaires.
// An array of documents to insert
const newProducts = [
{ name: "Mechanical Keyboard", brand: "Corsair", price: 129.99, inStock: false },
{ name: "Gaming Headset", brand: "Razer", price: 99.99, inStock: true },
{ name: "Webcam", brand: "LogiTech", price: 79.99, inStock: true }
];
// Insert the array of documents into the 'products' collection
db.products.insertMany(newProducts);
Lire des données (find)
La méthode find() est votre outil principal pour récupérer des documents d’une collection. Lorsqu’elle est appelée, find() ne renvoie pas directement les documents, mais un curseur. C’est une manière efficace de traiter de grands jeux de résultats sans tout charger en mémoire d’un coup.
L’appel le plus simple à find() ne prend aucun argument et renvoie un curseur sur tous les documents de la collection.
// Find and return a cursor to all documents in the 'products' collection
db.products.find();
Voici à quoi ressemble cet objet curseur dans mongosh (le shell MongoDB) et comment l’utiliser :
// Find all products and assign the returned cursor to a variable
const productCursor = db.products.find();
// The variable 'productCursor' now holds the cursor object, not the documents themselves.
// To get the documents, you need to iterate over the cursor.
// You can convert the cursor to an array to see all the documents
const allProducts = productCursor.toArray();
console.log(allProducts);
// Or, you can manually iterate through the documents
while (productCursor.hasNext()) {
const product = productCursor.next();
console.log(product);
}
Le curseur est un objet avec diverses méthodes comme toArray(), hasNext() et next() qui permettent de récupérer et de traiter les documents retournés.
Mettre à jour des données (update)
Pour modifier des documents existants, utilisez les méthodes update. Elles prennent deux arguments : un filtre pour sélectionner les documents à modifier et un opérateur de mise à jour pour préciser les changements. Un opérateur courant est $set, qui définit la valeur d’un champ.
updateOne()
Cette méthode met à jour le premier document correspondant au filtre.
// Update the 'Wireless Mouse' document to set its price to 39.99
db.products.updateOne(
{ name: "Wireless Mouse" }, // Filter to find the document
{ $set: { price: 39.99 } } // Update operator
);
updateMany()
Cette méthode met à jour tous les documents correspondant au filtre donné.
// Update all 'LogiTech' brand products to be in stock
db.products.updateMany(
{ brand: "LogiTech" }, // Filter to find the documents
{ $set: { inStock: true } } // Update operator
);
Supprimer des données (delete)
Pour supprimer des documents, utilisez les méthodes delete, qui acceptent également un filtre pour déterminer quels documents retirer.
deleteOne()
Cette méthode supprime le premier document correspondant au filtre.
// Delete the 'Webcam' document
db.products.deleteOne({ name: "Webcam" });
deleteMany()
Cette méthode supprime tous les documents correspondant au filtre. Pour supprimer tous les documents d’une collection, passez un filtre vide {}.
// Delete all documents that are not in stock
db.products.deleteMany({ inStock: false });
Récupération ciblée : filtres de requête
Les filtres de requête font la force de MongoDB. Ils constituent le premier argument des méthodes find() et update et vous permettent de cibler précisément les documents à traiter.
Opérateurs de comparaison
Ces opérateurs comparent la valeur d’un champ à une valeur donnée.
$eq (égal à)
Recherche les documents où un champ est égal à une valeur.
// Find all products that are made by 'Razer'
db.products.find({ brand: { $eq: "Razer" } });
// This can be simplified to:
// db.products.find({ brand: "Razer" });
$gt et $gte (strictement supérieur, supérieur ou égal)
Trouvent les documents où la valeur d’un champ est strictement supérieure ($gt) ou supérieure ou égale ($gte) à une valeur donnée.
// Find all products with a price greater than 100
db.products.find({ price: { $gt: 100 } });
$lt et $lte (strictement inférieur, inférieur ou égal)
Trouvent les documents où la valeur d’un champ est strictement inférieure ($lt) ou inférieure ou égale ($lte) à une valeur donnée.
// Find all products with a price less than or equal to 50
db.products.find({ price: { $lte: 50 } });
$ne (différent de)
$ne trouve les documents où un champ est différent d’une valeur donnée.
// Find all products that are NOT made by 'LogiTech'
db.products.find({ brand: { $ne: "LogiTech" } });
$in et $nin (dans un tableau, pas dans un tableau)
Trouvent les documents où la valeur d’un champ est présente ($in) ou absente ($nin) d’un tableau de valeurs.
// Find all products from 'Razer' or 'Corsair'
db.products.find({ brand: { $in: ["Razer", "Corsair"] } });
Opérateurs logiques
Les opérateurs logiques combinent plusieurs conditions pour créer des requêtes complexes.
$and
$and combine des conditions via un ET logique. Toutes les conditions doivent être vraies.
// Find all products with a price greater than 50 AND are in stock
db.products.find({ $and: [{ price: { $gt: 50 } }, { inStock: true }] });
// This can be simplified by just listing the conditions:
// db.products.find({ price: { $gt: 50 }, inStock: true });
$or
Combine des conditions via un OU logique. Au moins une condition doit être vraie.
// Find all products with a brand of 'Corsair' OR a price less than 40
db.products.find({ $or: [{ brand: "Corsair" }, { price: { $lt: 40 } }] });
Opérateurs d’élément et d’évaluation
Ces opérateurs offrent encore plus de souplesse pour filtrer.
$exists
$exists correspond aux documents qui contiennent un champ donné.
// Find all documents that have an 'inStock' field
db.products.find({ inStock: { $exists: true } });
$regex
Permet d’utiliser des expressions régulières pour rechercher des motifs dans les chaînes.
// Find all product names that start with 'Wireless'
db.products.find({ name: { $regex: /^Wireless/ } });
Façonner la sortie : projection
Lors d’une opération find(), vous pouvez ne récupérer qu’un sous-ensemble de champs. C’est la projection, second argument passé à find(). Elle réduit la quantité de données transférées et traitées.
Inclure des champs
Indiquez les champs à retourner en leur attribuant la valeur 1.
// Find all products and return only the 'name' and 'price' fields
db.products.find({}, { name: 1, price: 1 });
Exclure des champs
À l’inverse, masquez des champs en leur attribuant la valeur 0.
// Find all products and hide the 'inStock' field
db.products.find({}, { inStock: 0 });
Le champ _id est toujours renvoyé par défaut sauf exclusion explicite.
Le champ _id
Pour masquer le champ _id, vous devez explicitement le définir à 0.
// Find all products, returning only 'name' and 'price', and hiding '_id'
db.products.find({}, { _id: 0, name: 1, price: 1 });
Transformation avancée des données : pipelines d’agrégation
L’agrégation est un cadre puissant de traitement des données dans MongoDB. Un pipeline d’agrégation est une série d’étapes qui traitent les documents et transmettent les résultats de l’une à l’autre.
$match
Une étape $match filtre les documents selon un filtre de requête, comme dans find(). C’est souvent la première étape pour réduire le volume à traiter.
// Find all products with a brand of 'LogiTech'
db.products.aggregate([
{ $match: { brand: "LogiTech" } }
]);
$group
L’étape $group regroupe les documents par une expression _id donnée et permet d’appliquer des accumulateurs, comme le calcul d’une somme ou d’une moyenne.
// Group products by brand and calculate the total number of products for each brand
db.products.aggregate([
{ $group: { _id: "$brand", totalProducts: { $sum: 1 } } }
]);
$project
Une étape $project reconfigure chaque document, comme une projection dans find() : ajout ou suppression de champs, manipulation des données.
// Project a new field 'nameAndPrice' for each document
db.products.aggregate([
{ $project: { name: 1, price: 1, nameAndPrice: { $concat: ["$name", " (", "$price", ")"] } } }
]);
$sort
L’étape $sort réordonne les documents selon un champ. La valeur 1 indique l’ordre croissant, -1 l’ordre décroissant.
// Sort all products by price in descending order
db.products.aggregate([
{ $sort: { price: -1 } }
]);
$limit et $skip
Ces étapes servent à la pagination. $skip ignore un nombre donné de documents au début du pipeline et $limit limite le nombre de documents transmis à l’étape suivante.
// Skip the first 10 products and then return the next 5
db.products.aggregate([
{ $skip: 10 },
{ $limit: 5 }
]);
Exemple de pipeline simple
Voici un exemple complet qui montre comment ces étapes fonctionnent ensemble.
// Find the average price of all products that are currently in stock,
// grouped by brand.
db.products.aggregate([
{ $match: { inStock: true } }, // Filter for products in stock
{ $group: { _id: "$brand", averagePrice: { $avg: "$price" } } } // Group and calculate average price
]);
Booster les performances : indexation
Les index sont des structures de données spéciales qui stockent une portion restreinte et facilement parcourable des données d’une collection. Ils améliorent fortement les performances des requêtes en permettant à MongoDB de retrouver rapidement les documents sans balayer toute la collection.
createIndex()
Créez un index sur un champ fréquemment utilisé pour filtrer ou trier.
// Create a single-field index on the 'brand' field
db.products.createIndex({ brand: 1 });
La valeur 1 indique un ordre croissant. Vous pouvez utiliser -1 pour l’ordre décroissant, utile pour des tris dans ce sens.
Indexer un champ comme brand accélérera nettement les requêtes qui filtrent sur brand (par ex. db.products.find({ brand: "Razer" })), surtout à grande échelle.
Choisir les champs à indexer : points d’attention
Créez en priorité des index sur les champs fréquemment utilisés dans vos requêtes, par exemple dans un filtre find() ou dans un $match d’agrégation.
- Cardinalité : les champs avec de nombreuses valeurs uniques (forte cardinalité), comme l’adresse e‑mail d’un utilisateur, sont d’excellents candidats.
- Sélectivité des requêtes : un champ qui renvoie un sous-ensemble restreint de documents pour une requête donnée est également pertinent.
- Tri : si vous triez souvent vos résultats selon un champ, l’indexer accélérera grandement l’opération.
Impact sur les requêtes
Les index ont un impact majeur sur les performances. Une requête indexée est souvent des ordres de grandeur plus rapide que la même requête sans index.
// Conceptual illustration of performance difference
// Without an index on 'brand':
// MongoDB performs a full collection scan, checking every document.
// This is slow, especially with millions of documents.
db.products.find({ brand: "Razer" });
// With an index on 'brand':
// MongoDB uses the index to quickly locate and return only the matching documents.
// This is very fast.
db.products.find({ brand: "Razer" });
Pour optimiser davantage, utilisez db.collection.explain() afin d’analyser les performances et l’usage des index.
Conclusion : votre parcours vers la maîtrise de MongoDB
Vous venez de suivre un condensé sur l’API de requêtes de MongoDB ! Vous savez désormais exécuter les opérations CRUD, utiliser des filtres puissants pour cibler vos données, façonner la sortie via la projection et transformer vos données avec des pipelines d’agrégation. Vous disposez aussi des bases de l’indexation pour gagner en performance.
Ce guide pose un socle solide ; le meilleur moyen de progresser est la pratique. Expérimentez différentes requêtes et explorez la documentation complète pour découvrir des opérateurs et fonctionnalités avancés. Bon code !
FAQ sur l’API de requêtes MongoDB
Quelle est la principale différence entre find() et aggregate() ?
La méthode find() sert aux lectures simples, avec filtrage et projection optionnels. À l’inverse, aggregate() est un cadre puissant de traitement multi-étapes pour transformer, regrouper, trier et remodeler les documents de manière plus complexe. Tandis que find() lit les documents tels quels, aggregate() permet d’en tirer de nouveaux insights.
Pourquoi MongoDB renvoie-t-il un curseur avec find() plutôt que les documents eux-mêmes ?
Un curseur est une manière efficace de gérer de grands volumes de résultats. En renvoyant un curseur, MongoDB évite de charger tous les documents en mémoire d’un coup. C’est crucial pour la performance et l’évolutivité, notamment avec des millions de documents. Le curseur vous permet d’itérer à la demande, en récupérant les documents par lots.
Quand utiliser updateOne() vs updateMany() ?
Utilisez updateOne() lorsque vous ne devez modifier que le premier document correspondant au filtre, par exemple avec un identifiant unique. Employez updateMany() pour mettre à jour tous les documents qui répondent aux critères.
Comment les index améliorent-ils les performances des requêtes ?
Les index sont des structures de données spéciales qui conservent un sous-ensemble organisé des données d’une collection. Ils accélèrent fortement les requêtes en permettant à MongoDB de localiser rapidement les documents sans parcourir toute la collection. Au lieu de vérifier chaque document un à un, la base s’appuie sur l’index pour accéder directement aux correspondances, rendant l’opération bien plus rapide.
Puis-je combiner projection et agrégation ?
Oui, la projection est une composante clé des pipelines d’agrégation. L’étape $project sert à remodeler les documents, ajouter de nouveaux champs ou en supprimer. Elle est souvent utilisée après $match ou $group pour formater la sortie, et vous donner un contrôle fin sur la structure finale de vos données.
Karen est une ingénieure de données passionnée par la construction de plateformes de données évolutives. Elle a de l'expérience dans l'automatisation de l'infrastructure avec Terraform et est ravie de partager ses connaissances dans des articles de blog et des tutoriels. Karen est une bâtisseuse de communauté, et elle est passionnée par la promotion des liens entre les professionnels des données.
