Exercise 4 — Expressions Deep Dive
Topics: Arithmetic, comparison, boolean, control flow (
$cond,$switch), and array operators ($map,$filter,$reduce)Reading before you start: 08 - Expressions Overview, 09 - Arithmetic Operators, 10 - Comparison Operators, 11 - Boolean and Control Flow Operators, 12 - Array Operators
Database:
aggregation_lab— see Setup - Database
Part A — Arithmetic and Comparison Expressions
Task A1
For each project, compute a field budgetUtilization as (actualCost / estimatedCost) * 100. Also compute budgetRemaining as estimatedCost - actualCost. Project title, budgetUtilization, and budgetRemaining.
Hint: Use $divide and $multiply nested together for the percentage.
Task A2
For each employee, compute yearsOfExperience as (2025 - year_of_hire). Since we can’t easily extract the year from a date, approximate by computing salary / 5000 and call it salaryTier instead. Also compute doubledSalary as salary * 2.
Task A3
For each order, unwind items and compute lineTotal as price * quantity. Then compute discountedTotal as lineTotal * 0.9 (10% discount). Project product, lineTotal, and discountedTotal.
Task A4
For each task, add a field isHeavy using $gt to check if hours > 15. Also add cmpTo10 using $cmp to compare hours with 10.
Project title, hours, isHeavy, and cmpTo10.
Part B — Boolean and Control Flow
Task B1
For each employee, use $cond to add a field salaryCategory:
- If
salary >= 60000→"SENIOR" - Otherwise →
"STANDARD"
Project name, salary, and salaryCategory.
Task B2
For each project, use $cond to add a field overBudget:
- If
actualCost > estimatedCost→true - Otherwise →
false
Task B3
For each employee, use $switch to add a field experienceLevel:
- If
roleis"INTERN"→"JUNIOR" - If
roleis"DEVELOPER"→"MID" - If
roleis"LEAD"or"MANAGER"→"SENIOR" - Default →
"OTHER"
Hint: For the LEAD/MANAGER case, you can use $in inside $switch to check if the role is in a list, or you can have two separate case branches.
Task B4
For each task, use $cond with $and to add a field urgent:
- If the task is
"TODO"andhours >= 15→true - Otherwise →
false
Task B5
For each order, use $switch to add a field statusLabel:
"DELIVERED"→"Completed""SHIPPED"→"On the way""PROCESSING"→"Being prepared""CANCELLED"→"Cancelled"- Default →
"Unknown"
Part C — Array Operators
Task C1
Use $filter on the employees collection to add a field highRatings that contains only ratings greater than or equal to 4 from the ratings array.
Project name and highRatings.
Task C2
Use $map on the employees collection to add a field ratingsPlusOne where each rating in the ratings array is increased by 1.
Project name, ratings (original), and ratingsPlusOne.
Task C3
Use $filter on the projects collection to add a field completedMilestones that only includes milestones where completed is true.
Then add a field completedCount using $size on completedMilestones.
Project title, completedCount, and completedMilestones.
Task C4
Use $reduce on the employees collection to add a field skillString that concatenates all skills into a single comma-separated string.
Hint:
$reduce: {
input: "$skills",
initialValue: "",
in: {
$cond: [
{ $eq: ["$$value", ""] },
"$$this",
{ $concat: ["$$value", ", ", "$$this"] }
]
}
}Project name and skillString.
Task C5
For each order, use $map to transform the items array so that each item gets a new field lineTotal (price * quantity):
$map: {
input: "$items",
as: "item",
in: {
product: "$$item.product",
quantity: "$$item.quantity",
price: "$$item.price",
lineTotal: { $multiply: ["$$item.price", "$$item.quantity"] }
}
}Project _id, date, and the transformed items.
Part D — Combining Expressions with Stages
Task D1
Find all employees where the average of their ratings is above 4.0.
- Add a field
avgRatingusing$avgonratings - Match where
avgRating > 4(you’ll need$exprwith$gt— or just use$matchwith a regular comparison on the computed field) - Project
name,avgRating - Sort by
avgRatingdescending
Task D2
For each project:
- Add
teamSize,milestoneCount,completedMilestones(filtered array),completedCount - Add
completionRatecomputed as(completedCount / milestoneCount) * 100 - Use
$condto addonTrack:trueifcompletionRate >= 50, elsefalse - Project
title,status,teamSize,completionRate,onTrack - Sort by
completionRatedescending
Task D3
For each order:
- Use
$mapto addlineTotalto each item in theitemsarray - Use
$addFieldsto addorderTotalas the$sumof allitems.lineTotalvalues after the map — or use$reduceto sum them - Use
$condto addorderSize:"LARGE"iforderTotal > 500, else"SMALL" - Project
date,status,orderTotal,orderSize - Sort by
orderTotaldescending
Part E — Creative Challenge
Task E1
Employee scoring system: Design a pipeline that computes a “performance score” for each employee using any combination of expressions. Your score formula might consider: average rating, number of skills, salary relative to department average, etc. Be creative and explain your formula in a comment.
Task E2
Smart log analysis: Using the log_entries collection, write a pipeline that:
- Adds a field
severityusing$switchbased onlevel(ERROR=3, WARNING=2, INFO=1) - Filters to only entries with
severity >= 2 - Groups by
service, computingtotalSeverityandentryCount - Sorts by
totalSeveritydescending
This mimics a real monitoring dashboard that highlights the most problematic services.
Task E3
Order intelligence: Create a pipeline on orders that transforms each order into a “receipt” format:
- Each item should have its
lineTotalcomputed (use$map) - The order should have
orderTotal(sum of line totals) - Add
itemCount(number of items) - Use
$condto addfreeShipping: true iforderTotal > 1000 - Project everything cleanly and save to a collection
order_receipts
Reflection:
- How does
$mapdiffer from$unwind? When would you prefer one over the other?- Why is
$filtermore efficient than$unwind+$matchfor filtering array elements?- What are
$$valueand$$thisin$reduce, and how do they change as the reduction progresses?