#100DaysOfMERN - Day 48

Subscribe to my newsletter and never miss my upcoming articles

✏ 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:

aggregation-example-collection.png


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:

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:

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:

MongoDB Aggregation Framework


✏ 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 subsribe to my newsletter. Until next time 👋


✏ Previous Posts

You can find an overview of all previous posts with tags and tag search here:

#100DaysOfMERN - The App

No Comments Yet