MongoDB Aggregations: Finding Cooking Times with $min and $max

In this series we will explore different operators in the MongoDB Aggregation Framework via the context of a collection of recipes.

MongoDB Aggregations Series

Let’s say we’re making a brand new recipes website. Knowing the cooking times can help us categorize recipes into quick meals, slow-cooked dishes, or anything in between. MongoDB’s $min and $max aggregation operators allow you to extract minimum and maximum values across documents, making it easy to answer questions like:

“What’s the quickest recipe?” or “What’s the longest cooking recipe?”

In this post, we’ll walk through how to use $min and $max to find minimum and maximum cooking times within a recipe collection.

Why Use $min and $max for Cooking Times?

To start off let’s take into account three possible User Stories for our new website:

“As a User I want to create recipe filters …”

For busy users who need quick meal ideas

“As a User I want to highlight slow-cooked recipes …”

For special categories like soups, stews, or roasts

“As a Content Creator I want to use an analytics feature, to provide insights on average cooking times or to recommend recipes …”

For an internal user that helps generate content for our site.

With MongoDB, you can do all of this directly within your aggregation pipeline, saving time and improving efficiency.

Setting Up the Data

Let’s say you have a recipe collection with documents structured something like this:

{
  "_id": {
    "$oid": "636821387dd21c28fda4939f"
  },
  "title": "Split Pea Soup",
  "calories_per_serving": 158,
  "prep_time": 10,
  "cook_time": 300,
  "ingredients": [
    {
      "name": "peas",
      "quantity": {
        "amount": 1,
        "unit": "cup"
      },
      "vegetarian": true
    },
    ...
    {
      "name": "ham hock",
      "quantity": 1,
      "vegetarian": false,
      "optional": true
    }
  ],
  "directions": [
    "Pick over and wash the vegetable and soak several hours or overnight.",
    "Drain and add measured water and small onion, with ham hock if desired.",
    ...
  ],
  "rating": [4,4,4,4,2,5,3],
  "rating_avg": 3.71,
  "servings": 6,
  "tags": ["soup", "easy", "peas", "vegetarian"],
  "type": "Dinner",
  "vegetarian_option": true
}

Each recipe document includes a cook_time field representing the cooking time in minutes. Our goal is to find the shortest and longest cooking times across all recipes.

Using $min and $max in an Aggregation Pipeline

MongoDB’s aggregation framework lets us efficiently calculate these values across documents using $group, $min, and $max. Here’s a breakdown of how each operator works:

  • $min: Finds the smallest value in a specified field.
  • $max: Finds the largest value in a specified field.
  • $group: Groups documents by a specific field or no grouping at all (i.e., by null) to apply aggregations across the entire collection.

Let’s build an aggregation pipeline to find the minimum and maximum cooking times for all recipes.

Step 1: Finding the Minimum Cooking Time

To find the shortest cooking time in the collection, we’ll set up an aggregation pipeline that groups all documents and uses $min to return the smallest cook_time value.

> db.recipes.aggregate([
  {
    $group: { _id: null, minCookTime: { $min: "$cook_time" } },
  },
])

$group

We’re grouping by null, which means all documents are aggregated together rather than by a specific field.

minCookTime: { $min: "$cook_time" }

We’re calculating the minimum cook_time across all documents in the collection and setting it as minCookTime in the output (note: this will not update your actual documents, just the output).

Output Example:

{ "_id": null, "minCookTime": 15 }

This output tells us the shortest cooking time in our recipe collection is 15 minutes.

Step 2: Finding the Maximum Cooking Time

Now, let’s find the longest cooking time in the collection. We’ll use a similar pipeline, replacing $min with $max:

> db.recipes.aggregate([
  { $group: { _id: null, maxCookTime: { $max: "$cook_time" } } },
])

maxCookTime: { $max: "$cook_time" }

This calculates the maximum cook_time across all documents and sets it as maxCookTime.

Output Example:

{ "_id": null, "maxCookTime": 360 }

This output indicates the longest cooking time in our collection is 360 minutes (6 hours).

Step 3: Combining Minimum and Maximum Calculations

To get both minimum and maximum cooking times in a single query, we can combine $min and $max in one pipeline stage:

> db.recipes.aggregate([
  {
    $group: {
      _id: null,
      minCookTime: { $min: "$cook_time" },
      maxCookTime: { $max: "$cook_time" },
    },
  },
])

This pipeline groups all documents together and calculates both the minimum and maximum cooking times using $min and $max in the same $group stage makes it more efficient by reducing the need to run multiple queries.

Output Example:

{
  "_id": null,
  "minCookTime": 15,
  "maxCookTime": 360
}

Step 4: Calculating Total Time (Prep + Cook Time)

Often, users are interested in the total time it takes to make a recipe (including both preparation and cooking times). We can modify our pipeline to calculate total_time by adding prep_time and cook_time for each recipe document. This involves using $addFields to calculate a combined total_time field before applying $min and $max.

Here’s how you could do it:

> db.recipes.aggregate([
  { $addFields: { total_time: { $add: ["$prep_time", "$cook_time"] } } },
  {
    $group: {
      _id: null,
      minTotalTime: { $min: "$total_time" },
      maxTotalTime: { $max: "$total_time" },
    },
  },
])

$addFields

We add a total_time field to each document, which is the sum of prep_time and cook_time.

minTotalTime and maxTotalTime: Using $min and $max on total_time, we calculate the shortest and longest total times across all recipes.

Output Example:

{
  "_id": null,
  "minTotalTime": 25,
  "maxTotalTime": 370 
}

This output tells us that the shortest recipe (prep + cook) time is 25 minutes, and the longest is 370 minutes.

Practical Applications for Total Time Calculations

With total times at your disposal, you can build more user-friendly features:

Quick Recipe Suggestions

Use minTotalTime to show fast recipes under 30 minutes.

Long Cooking Recipes

Filter recipes based on maxTotalTime for users who are interested in weekend cooking projects.

Recipe Sorting

Sort recipes by total_time to show users options that fit their time constraints.

Cooking Time Ranges

Combine these calculations with $avg to give users a range of cooking times across your collection.

Advanced Tip: Adding Filters for Specific Recipe Types

What if you only want the minimum and maximum cooking times for a specific type of recipe, like “Dinner” recipes? You can add a $match stage before $group to filter the documents first:

> db.recipes.aggregate([
  { $match: { type: "Dinner" } },
  {
    $group: {
      _id: null,
      minCookTime: { $min: "$cook_time" },
      maxCookTime: { $max: "$cook_time" },
    },
  },
])

This pipeline first filters documents where type is "Dinner" and then calculates the minimum and maximum cooking times within that subset.

Conclusion

MongoDB’s $min and $max operators are powerful tools for quickly finding the smallest and largest values in a dataset. In a recipe application, they help you analyze cooking times, create specialized filters, and provide users with useful insights into recipe duration.

By combining $min, $max, and other operators like $match, you can build dynamic features that make your recipe collection more accessible and informative.

Experiment with $min and $max in your own MongoDB collections, and watch how these simple aggregations can enhance your app’s functionality and user experience!

,

MongoDB for Jobseekers Book

If you’re fascinated by the intricacies of MongoDB and yearn to explore its limitless possibilities further, I invite you to delve into my comprehensive book, “MongoDB for Jobseekers.”

This book is your passport to unlocking MongoDB’s full potential, whether you’re a beginner or an experienced enthusiast. Seamlessly navigate the intricacies of data management, uncover advanced techniques, and gain insights that will elevate your proficiency.

Available on Amazon and other leading platforms, “MongoDB for Jobseekers” offers a comprehensive roadmap for honing your MongoDB skills. As you embark on your journey through the world of databases, this book will be your trusted companion, guiding you towards mastery and helping you stand out in the competitive landscape.