Aller au contenu

MongoDB : requêtes et agrégation

Requêtes sur les collections clients et commandes. Tout se passe en JavaScript dans mongosh, dans la base boutique (use boutique).

db.clients.insertOne({
nom: 'Alice Martin',
email: 'alice@exemple.com',
ville: 'Lyon',
tags: ['vip'],
});
db.clients.insertMany([
{
nom: 'Bruno Durand',
email: 'bruno@exemple.com',
ville: 'Paris',
tags: ['web'],
},
{
nom: 'Chloé Petit',
email: 'chloe@exemple.com',
ville: 'Lyon',
tags: ['web', 'mobile'],
},
{ nom: 'David Moreau', email: 'david@exemple.com', tags: [] },
]);
const alice = db.clients.findOne({ email: 'alice@exemple.com' });
db.commandes.insertMany([
{
client_id: alice._id,
montant: 49.9,
statut: 'payee',
passee_le: new Date(),
},
{
client_id: alice._id,
montant: 120,
statut: 'nouvelle',
passee_le: new Date(),
},
{
client_id: db.clients.findOne({ nom: 'Bruno Durand' })._id,
montant: 15.5,
statut: 'payee',
passee_le: new Date(),
},
]);

Le résultat contient les _id générés (insertedId, insertedIds).

db.clients.find();
db.clients.find({ ville: 'Lyon' });
db.clients.find({ ville: 'Lyon' }, { nom: 1, email: 1, _id: 0 }); // projection : champs affichés (1) ou masqués (0)
db.clients.findOne({ email: 'bruno@exemple.com' });
db.clients.find({ nom: /^a/i }); // expression régulière
db.clients.find({ ville: { $exists: false } }); // champ absent
db.clients.find().sort({ nom: -1 }).limit(2); // tri décroissant, 2 résultats
db.clients.find().sort({ nom: 1 }).skip(2).limit(2); // pagination
db.clients.countDocuments({ ville: 'Lyon' });
db.clients.distinct('ville');
Opérateur Sens Exemple
$eq, $ne égal, différent { statut: { $ne: "annulee" } }
$gt, $gte, $lt, $lte comparaisons { montant: { $gte: 20, $lt: 200 } }
$in, $nin dans, hors d’une liste { ville: { $in: ["Lyon", "Paris"] } }
$and, $or, $nor, $not logique { $or: [{ ville: "Lyon" }, { tags: "vip" }] }
$exists champ présent { ville: { $exists: true } }
$regex expression régulière { nom: { $regex: "^A" } }
$size taille d’un tableau { tags: { $size: 2 } }
$elemMatch élément de tableau satisfaisant plusieurs conditions { lignes: { $elemMatch: { produit: "Clavier", quantite: { $gte: 1 } } } }
db.commandes.find({ montant: { $gte: 20, $lt: 200 }, statut: 'payee' });
db.clients.find({ $or: [{ ville: 'Lyon' }, { tags: 'vip' }] });
db.clients.find({ tags: 'web' }); // un tableau contenant « web »
db.commandes.find({
passee_le: { $gte: new Date(Date.now() - 7 * 24 * 3600 * 1000) },
}); // 7 derniers jours
db.clients.updateOne(
{ email: 'david@exemple.com' },
{ $set: { ville: 'Marseille' } },
);
db.commandes.updateMany({ statut: 'nouvelle' }, { $set: { statut: 'payee' } });
db.clients.updateOne(
{ email: 'alice@exemple.com' },
{ $push: { tags: 'fidele' } },
);
db.clients.updateOne(
{ email: 'alice@exemple.com' },
{ $addToSet: { tags: 'vip' } },
); // sans doublon
db.clients.updateOne(
{ email: 'alice@exemple.com' },
{ $pull: { tags: 'fidele' } },
);
db.commandes.updateOne({}, { $inc: { montant: 5 } }); // incrémente
db.clients.updateOne({ email: 'david@exemple.com' }, { $unset: { ville: '' } }); // supprime un champ
db.clients.findOneAndUpdate(
{ email: 'bruno@exemple.com' },
{ $set: { ville: 'Nice' } },
{ returnDocument: 'after' },
);
Opérateur Effet
$set, $unset Définit ou supprime un champ
$inc Incrémente un nombre
$push, $addToSet, $pull Ajoute, ajoute sans doublon, retire un élément de tableau
$rename Renomme un champ
$currentDate Définit la date courante
db.clients.updateOne(
{ email: 'emma@exemple.com' },
{ $set: { nom: 'Emma Roux' }, $setOnInsert: { cree_le: new Date() } },
{ upsert: true },
);

Si aucun document ne correspond, il est créé (et $setOnInsert ne s’applique qu’à la création).

db.commandes.deleteOne({ statut: 'annulee' });
db.commandes.deleteMany({ statut: 'annulee' });
db.clients.findOneAndDelete({ email: 'emma@exemple.com' });

Une agrégation enchaîne des étapes qui transforment les documents (équivalent de GROUP BY et des jointures).

// Total et nombre de commandes par statut
db.commandes.aggregate([
{
$group: {
_id: '$statut',
nb: { $sum: 1 },
total: { $sum: '$montant' },
moyenne: { $avg: '$montant' },
},
},
{ $sort: { total: -1 } },
]);
// Clients ayant dépensé plus de 100
db.commandes.aggregate([
{ $match: { statut: { $ne: 'annulee' } } },
{ $group: { _id: '$client_id', total: { $sum: '$montant' } } },
{ $match: { total: { $gt: 100 } } },
]);
// Jointure avec $lookup : ajouter les informations du client à chaque commande
db.commandes.aggregate([
{
$lookup: {
from: 'clients',
localField: 'client_id',
foreignField: '_id',
as: 'client',
},
},
{ $unwind: '$client' },
{ $project: { _id: 0, montant: 1, statut: 1, client: '$client.nom' } },
]);
// Nombre de clients par ville
db.clients.aggregate([
{ $group: { _id: '$ville', nb: { $sum: 1 } } },
{ $sort: { nb: -1 } },
]);
Étape Rôle
$match Filtre (comme find) : à placer le plus tôt possible pour utiliser un index
$group Regroupe et calcule ($sum, $avg, $min, $max, $count, $push)
$project Choisit ou calcule des champs
$sort, $limit, $skip Tri et pagination
$lookup Jointure avec une autre collection
$unwind Éclate un tableau en un document par élément
$count Compte les documents en sortie

Les opérations sur un seul document sont atomiques. Les transactions multi-documents (session.startTransaction()) nécessitent un jeu de réplicas (replica set) : elles ne sont pas disponibles sur une instance simple (standalone).