Section 6: Advanced MongoDB

⚑ Aggregation Framework

Master data transformation pipelines with powerful aggregation stages, live console, and real-world analytics

🏭 The Tale of the Data Factory

Imagine you own a juice factory. Raw fruits come in, and finished juice bottles go out. But in between, there's a whole assembly line:

🍎 Stage 1: WASH (Filter out bad fruits)
🍎 Stage 2: PEEL (Remove unwanted parts)
🍎 Stage 3: JUICE (Extract the good stuff)
🍎 Stage 4: MIX (Combine with other ingredients)
🍎 Stage 5: BOTTLE (Package the final product)
🍎 Stage 6: COUNT (How many bottles per flavor?)

That's exactly what MongoDB's Aggregation Pipeline does with your data!

πŸ“Š Stage 1: $match - Filter documents (like washing fruits)
πŸ“Š Stage 2: $project - Select fields (like peeling)
πŸ“Š Stage 3: $group - Calculate totals (like mixing)
πŸ“Š Stage 4: $sort - Order results (like organizing bottles)
πŸ“Š Stage 5: $limit - Take top N (like selecting best batches)
πŸ“Š Stage 6: $lookup - Join collections (like adding labels)

❌ Without Aggregation: You fetch ALL documents, process them in your application code (slow, memory-intensive, inefficient!)

βœ… With Aggregation: MongoDB does the heavy lifting on the database server, sends you only the results you need (fast, efficient, scalable!)

πŸ’‘ That's the Aggregation Framework!

A pipeline of stages that transform your data step-by-step.
Each stage does one thing, passes results to the next stage.
Perfect for analytics, reports, dashboards, and complex queries! πŸš€

⚑ What is the Aggregation Framework?

The Aggregation Framework is MongoDB's powerful data processing pipeline. It lets you filter, transform, group, sort, and analyze documents using a series of stages. Think of it as SQL's GROUP BY, JOIN, and HAVING on steroids!

Pipeline Concept

An aggregation pipeline consists of one or more stages. Each stage transforms the documents as they pass through. The output of one stage becomes the input of the next.

db.collection.aggregate([
  { $match: { status: "active" } },      // Stage 1: Filter
  { $group: { _id: "$city", count: { $sum: 1 } } },  // Stage 2: Group
  { $sort: { count: -1 } },              // Stage 3: Sort
  { $limit: 10 }                          // Stage 4: Limit
])

Key Benefits:

  • πŸš€ Server-side processing (faster than client-side)
  • πŸ’ͺ Handles complex transformations
  • πŸ“Š Perfect for analytics and reporting
  • πŸ”— Can join multiple collections ($lookup)
  • ⚑ Optimized by MongoDB query planner

πŸ”§ Common Pipeline Stages

MongoDB offers 30+ aggregation stages. Here are the most important ones you'll use daily:

πŸ”

$match

Filters documents (like find()). Use early in pipeline for performance!

{ $match: { age: { $gte: 18 } } }
βœ‚οΈ

$project

Reshapes documents - include/exclude fields, create computed fields.

{ $project: { name: 1, age: 1 } }
πŸ“¦

$group

Groups documents by field and performs calculations (sum, avg, count).

{ $group: { _id: "$city" } }
πŸ”„

$sort

Orders documents by field(s). 1 = ascending, -1 = descending.

{ $sort: { score: -1 } }
βœ‹

$limit

Limits the number of documents passed to next stage.

{ $limit: 10 }
⏭️

$skip

Skips first N documents. Useful for pagination.

{ $skip: 20 }
πŸ”—

$lookup

Performs a left outer join with another collection (like SQL JOIN).

{ $lookup: { from: "orders" } }
πŸ“€

$unwind

Deconstructs an array field, creating one document per array element.

{ $unwind: "$tags" }
πŸ”’

$count

Counts the number of documents and returns the count.

{ $count: "totalUsers" }
βž•

$addFields

Adds new computed fields to documents without removing existing fields.

{ $addFields: { fullName: "$name" } }
πŸ“Š

$bucket

Categorizes documents into buckets based on field values.

{ $bucket: { groupBy: "$age" } }
🎭

$facet

Processes multiple pipelines in parallel within a single stage.

{ $facet: { stats: [...] } }

πŸ’» Live Aggregation Console

Try aggregation pipelines on real data! Click any example below or write your own pipeline.

MongoDB Aggregation Shell
Ready

Sample Sales Data (12 documents)

Try These Examples (Click to Load)

Pipeline Input
Press Ctrl+Enter to run your pipeline
Results Output
// Results will appear here... // Your aggregation pipeline results will be displayed in formatted JSON // Try clicking an example or write your own!

πŸ“Š Pipeline Execution Flow

Watch how documents flow through each stage of your pipeline

🎯 Common Aggregation Patterns

Here are the most frequently used aggregation patterns in real applications:

Pattern 1: Count by Category

How many documents in each category? Perfect for dashboards and analytics.

// Count sales by product
db.sales.aggregate([
  { $group: {
      _id: "$product",
      count: { $sum: 1 },
      total: { $sum: "$amount" }
  }},
  { $sort: { total: -1 } }
])

// Result: { _id: "Laptop", count: 3, total: 3600 }

Pattern 2: Sum/Average Calculations

Calculate totals, averages, min, max for numerical fields.

// Total and average sales by month
db.sales.aggregate([
  { $group: {
      _id: { $month: "$date" },
      totalSales: { $sum: "$amount" },
      avgSale: { $avg: "$amount" },
      minSale: { $min: "$amount" },
      maxSale: { $max: "$amount" },
      transactions: { $sum: 1 }
  }},
  { $sort: { _id: 1 } }
])

// Result: { _id: 1, totalSales: 5500, avgSale: 916.67, ... }

Pattern 3: Filter β†’ Group β†’ Sort

The most common pipeline: filter first, then aggregate, finally sort.

// Top 5 customers by completed orders
db.orders.aggregate([
  { $match: { status: "completed" } },     // Filter
  { $group: {
      _id: "$customerId",
      totalSpent: { $sum: "$amount" },
      orderCount: { $sum: 1 }
  }},
  { $sort: { totalSpent: -1 } },           // Sort
  { $limit: 5 }                             // Top 5
])

// Performance tip: Always $match early to reduce documents!

Pattern 4: $lookup (Join Collections)

Join data from multiple collections like SQL JOIN.

// Get orders with customer details
db.orders.aggregate([
  { $lookup: {
      from: "customers",           // Join with customers collection
      localField: "customerId",    // Field in orders
      foreignField: "_id",         // Field in customers
      as: "customerInfo"           // Output array name
  }},
  { $unwind: "$customerInfo" },    // Convert array to object
  { $project: {
      orderDate: 1,
      amount: 1,
      customerName: "$customerInfo.name",
      customerEmail: "$customerInfo.email"
  }}
])

// Result: { orderDate: ..., amount: 100, customerName: "Alice", ... }

Pattern 5: $unwind Arrays

Break down array fields into separate documents for analysis.

// Document: { name: "Alice", tags: ["VIP", "Premium", "Loyalty"] }

db.users.aggregate([
  { $unwind: "$tags" },            // Creates 3 documents, one per tag
  { $group: {
      _id: "$tags",
      userCount: { $sum: 1 }
  }},
  { $sort: { userCount: -1 } }
])

// Result: { _id: "VIP", userCount: 15 }
//         { _id: "Premium", userCount: 8 }
//         { _id: "Loyalty", userCount: 12 }

Pattern 6: Date Aggregations

Group by date parts (year, month, day) for time-series analysis.

// Sales by year and month
db.sales.aggregate([
  { $group: {
      _id: {
        year: { $year: "$date" },
        month: { $month: "$date" }
      },
      totalSales: { $sum: "$amount" },
      avgSale: { $avg: "$amount" }
  }},
  { $sort: { "_id.year": 1, "_id.month": 1 } }
])

// Result: { _id: { year: 2024, month: 1 }, totalSales: 15000, ... }

🌍 Real-World Scenarios

See how aggregation solves real business problems:

1. E-Commerce Sales Dashboard

Requirement: Show total sales, top products, and revenue trends

// Complete dashboard query
db.orders.aggregate([
  // Only completed orders
  { $match: { status: "completed" } },
  
  // Add year-month field
  { $addFields: {
      yearMonth: {
        $dateToString: { format: "%Y-%m", date: "$orderDate" }
      }
  }},
  
  // Group by time and product
  { $group: {
      _id: {
        period: "$yearMonth",
        product: "$productName"
      },
      revenue: { $sum: "$amount" },
      quantity: { $sum: "$quantity" },
      orderCount: { $sum: 1 }
  }},
  
  // Sort by period and revenue
  { $sort: { "_id.period": -1, "revenue": -1 } },
  
  // Format output
  { $project: {
      _id: 0,
      period: "$_id.period",
      product: "$_id.product",
      revenue: 1,
      quantity: 1,
      orders: "$orderCount",
      avgOrderValue: { $divide: ["$revenue", "$orderCount"] }
  }}
])

// Perfect for charts and reports!

2. Customer Segmentation

Requirement: Categorize customers into VIP, Regular, Inactive

// Segment customers by purchase behavior
db.customers.aggregate([
  // Join with orders
  { $lookup: {
      from: "orders",
      localField: "_id",
      foreignField: "customerId",
      as: "orders"
  }},
  
  // Calculate metrics
  { $addFields: {
      totalSpent: { $sum: "$orders.amount" },
      orderCount: { $size: "$orders" },
      lastOrderDate: { $max: "$orders.orderDate" }
  }},
  
  // Categorize customers
  { $addFields: {
      segment: {
        $switch: {
          branches: [
            { case: { $gte: ["$totalSpent", 5000] }, then: "VIP" },
            { case: { $gte: ["$totalSpent", 1000] }, then: "Regular" },
            { case: { $lt: ["$orderCount", 1] }, then: "Inactive" }
          ],
          default: "New"
        }
      }
  }},
  
  // Group by segment
  { $group: {
      _id: "$segment",
      customerCount: { $sum: 1 },
      totalRevenue: { $sum: "$totalSpent" },
      avgSpent: { $avg: "$totalSpent" }
  }},
  
  { $sort: { totalRevenue: -1 } }
])

// Result: { _id: "VIP", customerCount: 42, totalRevenue: 350000, ... }

3. Product Performance Report

Requirement: Which products are selling well? Which are slow?

// Comprehensive product analysis
db.orders.aggregate([
  // Last 90 days only
  { $match: {
      orderDate: { $gte: new Date(Date.now() - 90*24*60*60*1000) }
  }},
  
  // Unwind line items
  { $unwind: "$items" },
  
  // Group by product
  { $group: {
      _id: "$items.productId",
      productName: { $first: "$items.productName" },
      unitsSold: { $sum: "$items.quantity" },
      revenue: { $sum: { $multiply: ["$items.quantity", "$items.price"] } },
      orderCount: { $sum: 1 },
      avgPrice: { $avg: "$items.price" }
  }},
  
  // Calculate metrics
  { $addFields: {
      revenuePerUnit: { $divide: ["$revenue", "$unitsSold"] }
  }},
  
  // Categorize performance
  { $addFields: {
      performance: {
        $cond: {
          if: { $gte: ["$unitsSold", 100] },
          then: "Hot Seller",
          else: { $cond: {
            if: { $gte: ["$unitsSold", 20] },
            then: "Steady",
            else: "Slow Mover"
          }}
        }
      }
  }},
  
  { $sort: { revenue: -1 } }
])

// Use this for inventory decisions!

4. Leaderboard with Rankings

Requirement: Show top users with ranks and percentiles

// Gaming leaderboard with rankings
db.users.aggregate([
  // Active users only
  { $match: { status: "active" } },
  
  // Sort by score
  { $sort: { score: -1, level: -1 } },
  
  // Add rank using $setWindowFields (MongoDB 5.0+)
  { $setWindowFields: {
      sortBy: { score: -1, level: -1 },
      output: {
        rank: { $rank: {} },
        percentile: { $percentile: { input: "$score", p: [0.5], method: "approximate" } }
      }
  }},
  
  // Add rank labels
  { $addFields: {
      rankLabel: {
        $switch: {
          branches: [
            { case: { $lte: ["$rank", 10] }, then: "πŸ₯‡ Top 10" },
            { case: { $lte: ["$rank", 100] }, then: "πŸ₯ˆ Top 100" },
            { case: { $lte: ["$rank", 1000] }, then: "πŸ₯‰ Top 1000" }
          ],
          default: "Player"
        }
      }
  }},
  
  // Top 50 only
  { $limit: 50 },
  
  // Clean output
  { $project: {
      _id: 0,
      rank: 1,
      username: 1,
      score: 1,
      level: 1,
      rankLabel: 1
  }}
])

// Perfect for competitive games!

πŸ’Ό Interview Questions & Answers

Master these 6 aggregation questions to ace your MongoDB interview: