Chapter 18: MongoDB Aggregation $addFields
1. What does $addFields actually do? (Very clear teacher explanation)
$addFields does exactly one thing very well:
It adds new fields to the existing documents or overwrites existing fields with new calculated values while keeping ALL the original fields unchanged (unless you explicitly overwrite them).
Compare it side-by-side with $project:
| Feature | $project | $addFields | Winner for most real cases |
|---|---|---|---|
| Keeps original fields by default | No — you must list every field you want | Yes — all original fields stay automatically | $addFields |
| Can remove fields | Yes (set to 0) | No — cannot remove fields | $project |
| Can rename fields | Yes (newName: “$oldName”) | No — cannot rename (but can copy + remove later) | $project |
| Can create computed fields | Yes | Yes | Tie |
| Typical use case | Final shaping of output / hide many fields | Add calculations / flags / dates mid-pipeline | — |
Golden classroom rule (repeat after me):
Use $addFields when you want to enrich documents with new values but still need all (or most) of the original fields later in the pipeline.
Use $project when you are at the very end and want to clean up, hide, or completely reshape the final output.
2. Basic Syntax (Super simple)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
{ $addFields: { newField1: <expression>, newField2: <expression>, existingField: <new expression>, // ← overwrites if exists "nested.newField": <expression> } } |
3. Hands-on Examples — Using Our Movie Collection
|
0 1 2 3 4 5 6 |
use movieAnalytics2026 |
Example 1: Add simple flags & computed values
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
db.movies.aggregate([ { $addFields: { isBlockbuster: { $gte: ["$rating", 8.0] }, // new boolean ageInYears: { $floor: { $divide: [ { $subtract: [ new Date(), "$releaseDate" ] }, 1000 * 60 * 60 * 24 * 365 ] } }, // rough age ratingCategory: { $switch: { branches: [ { case: { $gte: ["$rating", 8.5] }, then: "Masterpiece" }, { case: { $gte: ["$rating", 7.5] }, then: "Great" }, { case: { $gte: ["$rating", 6.0] }, then: "Good" } ], default: "Average" } }, revenueDisplay: { $concat: ["₹", { $toString: "$revenue" }, " Cr"] } } }, { $limit: 3 }, { $project: { title: 1, rating: 1, isBlockbuster: 1, ratingCategory: 1, _id: 0 } } ]) |
→ All original fields (genres, year, country, etc.) are still there — we just added new ones.
Example 2: Add fields before $group (very common pattern)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
db.movies.aggregate([ // Step 1: Add useful computed fields { $addFields: { mainGenre: { $arrayElemAt: ["$genres", 0] }, // first genre isRecent: { $gte: ["$year", 2023] }, revenuePerRating: { $cond: { if: { $gt: ["$rating", 0] }, then: { $divide: ["$revenue", "$rating"] }, else: 0 } } } }, // Step 2: Now group using the new fields { $group: { _id: "$mainGenre", movieCount: { $sum: 1 }, avgRevenuePerRating: { $avg: "$revenuePerRating" }, recentMovies: { $sum: { $cond: [{ $eq: ["$isRecent", true] }, 1, 0] } } } }, { $sort: { movieCount: -1 } }, { $limit: 4 } ]) |
→ We needed those extra fields only for grouping — $addFields made it clean.
Example 3: Overwrite existing field (sometimes useful)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
db.movies.aggregate([ { $addFields: { rating: { $round: ["$rating", 1] } // overwrite original rating with rounded value } } ]) |
→ Original rating is replaced everywhere downstream.
4. Quick Comparison Table — When to Choose $addFields vs $project
| Situation | Recommended Stage | Why? |
|---|---|---|
| You need to add 2–3 calculated fields but keep everything else | $addFields | No need to list all original fields |
| Final output — hide 10+ fields, rename, reshape | $project | Cleaner final shape, can remove _id easily |
| Mid-pipeline — need new fields for next $group / $sort | $addFields | Preserve all data for later stages |
| Want to both add fields and remove some | $addFields + $project | Use $addFields first → $project at the end |
| Overwrite existing field with calculation | $addFields | Simple — just use same field name |
5. Mini Exercise — Try Right Now in mongosh!
- Add a field isSuperhit = true if rating ≥ 8.3
- Add genresCount = size of genres array
- Add titleWithYear = “Movie (year)” using $concat
- Add profitScore = revenue – (rating * 100) (dummy)
- Then $group by isSuperhit and count movies
Understood beta? $addFields is your best friend when you want to enrich documents step-by-step without losing any original information — it’s the stage that makes complex pipelines readable and maintainable.
Next class — what shall we cover?
- $addFields vs $project deep comparison with same pipeline
- Using $addFields inside $lookup (joined data enrichment)
- Date / string / math / conditional operators inside $addFields
- Or let’s finally build a complete “Movie Analytics Dashboard” pipeline using all stages we learned?
Tell me — class is ready for the next chapter! 🚀❤️
Any part of $addFields still confusing? Ask freely — we’ll do more live examples together 😄
