$match et $project : filtrer et remodeler
Les apprenants placeront $match au début de la chaîne de traitement pour améliorer les performances et utiliseront $project pour renommer et calculer de nouveaux champs.
$match et $project : filtrer et remodeler est une leçon MongoDB Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage MongoDB Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours MongoDB Academy comprend 4 leçons au total.
L’étape $match
L’étape $match est l’équivalent, dans le pipeline d’agrégation, du filtre de find(). Elle accepte la même syntaxe de requête — vérifications d’égalité, opérateurs de comparaison, opérateurs logiques, $regex, $elemMatch — et filtre le flux de documents en supprimant ceux qui ne correspondent pas. Les documents qui passent sont transmis à l’étape suivante ; les autres sont éliminés.
// $match uses the same syntax as find() filters
db.orders.aggregate([
{ $match: {
status: 'completed',
amount: { $gte: 100 },
createdAt: { $gte: new Date('2024-01-01') }
}}
]);
// Only orders matching ALL three conditions pass throughPlacez $match en premier pour utiliser un index
Lorsque $match est la première étape du pipeline, MongoDB peut utiliser un index pour appliquer le filtre, exactement comme une requête find(). Si $match apparaît après d’autres étapes, l’avantage de l’index est perdu, car le planificateur ne peut utiliser l’index que pour la première étape. Il s’agit de la règle de performance la plus importante lors de la conception d’un pipeline d’agrégation.
// GOOD: $match first -> uses index on userId
db.orders.aggregate([
{ $match: { userId: 'u1', status: 'active' } }, // index used here
{ $group: { _id: '$productId', count: { $sum: 1 } } }
]);
// BAD: $match after $group -> full collection scan
db.orders.aggregate([
{ $group: { _id: '$productId', count: { $sum: 1 } } },
{ $match: { userId: 'u1' } } // too late for index
]);Utiliser $match avec $text
L’opérateur de recherche en texte intégral $text ne peut être utilisé qu’à l’intérieur de $match, et uniquement lorsqu’il s’agit de la première étape du pipeline. Cette restriction existe parce que MongoDB doit transmettre la recherche textuelle à l’index de texte, ce qui se produit au niveau du plan de requête avant toute transformation effectuée par une étape. Après que $match a filtré le texte, vous pouvez projeter le score de texte et trier par pertinence dans les étapes suivantes.
db.articles.aggregate([
// $text in $match MUST be the first stage
{ $match: { $text: { $search: 'mongodb aggregation' } } },
{ $addFields: { score: { $meta: 'textScore' } } },
{ $sort: { score: -1 } },
{ $limit: 5 }
]);L’étape $project
L’étape $project remodèle les documents : vous pouvez inclure ou exclure des champs, renommer des champs et calculer des champs entièrement nouveaux à l’aide d’opérateurs d’expression. Elle transmet un document de sortie pour chaque document d’entrée, contrairement à $group, qui regroupe plusieurs documents en un seul. Une étape $project sert souvent à réduire les documents avant des étapes coûteuses ou à préparer la structure finale de la sortie.
db.users.aggregate([
{ $project: {
_id: 0, // exclude _id
name: 1, // include name
email: 1, // include email
// Exclude password - never send to client!
// (fields not listed are excluded when any field is included)
}}
]);Inclusion et exclusion dans $project
Comme les projections de find(), $project ne peut pas mélanger inclusion et exclusion dans une même étape, à l’exception de _id, qui peut toujours être explicitement exclu, même dans une projection par inclusion. Attribuez 1 à un champ pour l’inclure, 0 pour l’exclure, ou une expression pour le calculer et l’inclure. Les champs non mentionnés dans une projection par inclusion sont supprimés.
// Inclusion mode: list what you WANT
db.products.aggregate([{
$project: {
_id: 0, // OK to exclude _id in inclusion mode
name: 1,
price: 1
}
}]);
// Exclusion mode: list what you DON'T want
db.products.aggregate([{
$project: {
password: 0,
__v: 0
}
}]);
// Cannot mix: { name: 1, password: 0 } is an error (except _id)Calculer de nouveaux champs dans $project
La véritable puissance de $project réside dans le calcul de nouveaux champs dérivés à l’aide d’opérateurs d’expression. Vous pouvez renommer un champ en lui attribuant une référence de champ, effectuer des opérations arithmétiques, mettre en forme des chaînes ou utiliser des conditions, le tout côté serveur sans modifier les documents stockés. Les champs calculés n’existent que dans la sortie du pipeline ; les documents sous-jacents restent inchangés.
db.invoices.aggregate([
{ $project: {
invoiceNumber: '$_id', // rename _id to invoiceNumber
clientName: '$client.name', // flatten nested field
subtotal: 1,
tax: { $multiply: ['$subtotal', 0.08] }, // compute tax
total: { $add: ['$subtotal', { $multiply: ['$subtotal', 0.08] }] },
issued: { $dateToString: { format: '%Y-%m-%d', date: '$createdAt' } }
}}
]);Renommer et imbriquer des champs
Vous pouvez utiliser $project pour restructurer la forme du document : aplatir des champs imbriqués au niveau supérieur ou regrouper des champs plats dans un sous-document imbriqué. Cela permet d’aligner la sortie MongoDB sur le schéma de réponse d’une API différent de la structure des documents stockés, sans modifier la manière dont vous stockez les données.
// Document: { firstName: 'Alice', lastName: 'Smith', age: 30 }
// API wants: { name: { first, last }, age }
db.users.aggregate([{
$project: {
_id: 0,
name: {
first: '$firstName', // group into nested object
last: '$lastName'
},
age: 1
}
}]);
// Output: { name: { first: 'Alice', last: 'Smith' }, age: 30 }Utiliser $project avec des tableaux
$project prend en charge les expressions de tableau pour transformer ou filtrer les tableaux contenus dans les documents. Vous pouvez utiliser $map pour transformer chaque élément, $filter pour sélectionner les éléments qui correspondent à une condition, $slice pour extraire une partie du tableau ou $arrayElemAt pour accéder à un index précis. Ces opérations s’exécutent côté serveur sur le tableau complet, sans nécessiter plusieurs étapes de pipeline.
db.articles.aggregate([{
$project: {
title: 1,
// Keep only published tags
activeTags: {
$filter: {
input: '$tags',
as: 'tag',
cond: { $eq: ['$$tag.active', true] }
}
},
// First author only
leadAuthor: { $arrayElemAt: ['$authors', 0] },
// Uppercase each tag name
upperTags: { $map: { input: '$tags', as: 't', in: { $toUpper: '$$t' } } }
}
}]);Plusieurs étapes $match
Vous pouvez utiliser plusieurs étapes $match dans un même pipeline. Un schéma courant consiste à utiliser $match tôt pour tirer parti d’un index, puis $group ou $project pour calculer de nouveaux champs, et enfin un second $match pour filtrer selon ces valeurs calculées. Le premier $match bénéficie de l’utilisation de l’index ; le second filtre l’ensemble de résultats calculés.
db.orders.aggregate([
// First $match: uses index on userId
{ $match: { userId: 'u1' } },
// Compute revenue per product
{ $group: { _id: '$productId', revenue: { $sum: '$amount' } } },
// Second $match: filter computed revenue (no index possible here)
{ $match: { revenue: { $gte: 500 } } },
{ $sort: { revenue: -1 } }
]);Quand utiliser $addFields plutôt que $project
Un inconvénient fréquent de $project est qu’en mode inclusion, vous devez énumérer chaque champ que vous souhaitez conserver. Si vous voulez simplement ajouter de nouveaux champs sans supprimer les champs existants, utilisez plutôt $addFields (ou son alias $set). $addFields conserve tous les champs existants et ajoute ou remplace uniquement les champs indiqués, ce qui est beaucoup moins verbeux pour de simples ajouts de champs calculés.
// $project: must list ALL fields you want to keep
db.users.aggregate([{ $project: { name: 1, email: 1, age: 1,
ageGroup: { $cond: { if: { $lt: ['$age', 18] }, then: 'minor', else: 'adult' } }
}}]);
// $addFields: keeps all fields, just adds ageGroup
db.users.aggregate([{ $addFields: {
ageGroup: { $cond: { if: { $lt: ['$age', 18] }, then: 'minor', else: 'adult' } }
}}]);
// All original fields (name, email, age, etc.) are preservedPerformances du pipeline : utiliser $project tôt
Placer une étape $project tôt dans le pipeline afin de supprimer les champs inutiles réduit la mémoire et la bande passante utilisées par les étapes suivantes. Si les étapes ultérieures n’ont pas besoin d’un grand tableau imbriqué ou d’un long champ textuel, excluez-les avec un $project ou un $unset placé tôt. Cela a un impact particulièrement important lorsque les documents sont volumineux et que le pipeline comporte de nombreuses étapes.
db.articles.aggregate([
{ $match: { status: 'published' } },
// Trim large fields early before expensive stages
{ $project: {
title: 1,
authorId: 1,
publishedAt: 1,
categoryId: 1,
// Exclude: body (could be 50KB), rawHtml (100KB)
// This reduces memory in all subsequent stages
}},
{ $lookup: { from: 'authors', localField: 'authorId', foreignField: '_id', as: 'author' } },
{ $sort: { publishedAt: -1 } },
{ $limit: 20 }
]);Vérification rapide
Vérifiez votre compréhension de $match et de $project dans le pipeline d’agrégation.
Récapitulatif de la leçon
Dans cette leçon, vous avez appris que $match filtre le flux de documents en utilisant la même syntaxe de requête que find() et doit être placé en premier pour tirer parti des index, que $project remodèle les documents en incluant, excluant et calculant des champs, et que $addFields est préférable lorsque vous souhaitez uniquement ajouter des champs sans énumérer tous les champs existants. Nous allons maintenant étudier $group pour effectuer des agrégations et calculer des totaux.
Apprends JavaScript avec un tuteur IA — gratuit
Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.
- Cours
- 30
- Leçons
- 120
Questions Fréquemment Posées
La leçon « $match et $project : filtrer et remodeler » est-elle gratuite ?
Oui — le texte complet de « $match et $project : filtrer et remodeler » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours MongoDB Academy, passe à CoddyKit PRO. Le cours MongoDB Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « $match et $project : filtrer et remodeler » ?
Les apprenants placeront $match au début de la chaîne de traitement pour améliorer les performances et utiliseront $project pour renommer et calculer de nouveaux champs. Tu pratiques MongoDB Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer MongoDB Academy ?
Aucune expérience préalable n'est requise. MongoDB Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.
Combien de temps prend la leçon « $match et $project : filtrer et remodeler » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon MongoDB Academy ?
Oui. Chaque leçon MongoDB Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Concepts des chaînes de traitement : étapes, opérateurs et expressions
- $match et $project : filtrer et remodeler
- $group : agréger et calculer des totaux
- $sort, $limit et $skip dans la chaîne de traitement