✏ MongoDB Aggregation: $match stage
The $match
stage is basically the same as using .find({ condition })
. Using $match
on its own doesn't perform any aggregation yet, it's only the first step, to select a subset of documents in a collection. Below is a list of examples, covering all kinds of combinations to perform a query with $match
.
For easier reference, this is the collection again that the examples are referring to:
To get a specific recipe, you add a field/expression pair inside the curly braces:
Recipe.aggregate([
{ $match: { title: 'Soup' } }
]);
// Soup
To filter nested fields, wrap the field in quotes:
Recipe.aggregate([
{ $match: { 'info.category': 'lunch' } }
]);
// Soup, Pasta
Passing a second condition is evaluated with an implicit AND. To search for category "lunch" and a cooking time of less than "10" (minutes):
Recipe.aggregate([
{ $match: { 'info.category': 'lunch', 'info.time.cooking': { $lt: 10 } } }
]);
// Pasta
This is a shorthand for explicitly using the $and
operator with an array:
Recipe.aggregate([
{ $match: { $and: [
{ 'info.category': 'lunch' },
{ 'info.time.cooking': { $lt: 10 } }
] } }
]);
// Pasta
To search for recipes where either the preparation time or the cooking time is "0", use the $or
operator:
Recipe.aggregate([
{ $match: { $or: [
{ 'info.time.preparation': 0 },
{ 'info.time.cooking': 0 }
] } }
]);
// Salad, Dessert
To search with OR in the same field, for example recipes with title "Soup" OR "Salad", use the Array $in
operator:
Recipe.aggregate([
{ $match: { title: { $in: ['Soup', 'Salad'] } } }
]);
// Soup, Salad
To search for recipes that have only one ingredient: js Recipe.aggregate([ { $match: { ingredients: { $size: 1 } } } ]); // Dessert
Note that $size
needs a number as value, comparisons ({ $gt: 1 }
) are invalid.
To compare two fields within the same document, use the $expr
operator. To find recipes where the preparation time is greater than or equal to the cooking time: js Recipe.aggregate([ { $match: { $expr: { $gte: [ '$info.time.preparation', '$info.time.cooking' ] } } } ]); // Salad, Dessert
Note that the comparison is made using a reference to a field. References are indicated by wrapping the field name in quotes, preceded by a $
.
To find all recipes where "pepper" is in the ingredient array:
Recipe.aggregate([
{ $match: { 'ingredients.name': 'pepper' } }
]);
// Soup, Salad
To find recipes that have either "pepper" or "salt" as ingredient:
Recipe.aggregate([
{ $match: { 'ingredients.name': { $in: ['pepper', 'salt'] } } }
]);
// Soup, Pasta, Salad
To find recipes from categories "side" or "dessert", where the cooking time is lesser than the preparation time:
Recipe.aggregate([
{ $match: {
'info.category': { $in: ['side', 'dessert'] },
$expr: { $lt: ['$info.time.cooking', '$info.time.preparation'] }
}
}
]);
// Salad
To find recipes that either contain "pesto" or "oil", or have a preparation and cooking time of "0":
Recipe.aggregate([
{ $match: {
$or: [
{ 'ingredients.name': { $in: ['pesto', 'oil'] } },
{ 'info.time.preparation': 0, 'info.time.cooking': 0 }
]}
}
]);
// Pasta, Salad, Dessert
This is getting really contrived, but the list might be helpful if you're looking for a certain search pattern. As mentioned, all of the objects that define what $match
should look for in the above examples can also be passed into the .find({})
method.
Next post: The $group
stage.
✏ Resources
I highly recommend this YouTube playlist:
✏ Recap
This post covered:
- MongoDB aggregation:
$match
stage
✏ Thanks for reading!
I do my best to thoroughly research the things I learn, but if you find any errors or have additions, please leave a comment below, or @ me on Twitter. If you liked this post, I invite you to subscribe to my newsletter. Until next time 👋
✏ Previous Posts
You can find an overview of all previous posts with tags and tag search here: