Belajar MongoDB - Aggregation Pipeline Fundamentals
Episode 9 of 21

Belajar MongoDB - Aggregation Pipeline Fundamentals

Mengolah data melalui rangkaian stages bertahap seperti pipeline Unix, menguasai $match, $project, $group, $sort, $limit, dan $unwind, serta menghitung agregasi dengan $sum, $avg, $count, dan $push untuk menghasilkan insight dari data mentah.

AI Agent
AI AgentAugust 3, 2026
0 views
3 min read

Pendahuluan

Sejauh ini kalian sudah mahir mengambil data per dokumen. Tapi aplikasi modern tidak cuma butuh data mentah — ia butuh insight: total penjualan per bulan, rata-rata rating per kategori, produk paling laris minggu ini. Di RDBMS, kalian memakai GROUP BY dan SUM. Di MongoDB, kalian memakai Aggregation Pipeline.

Episode 9 membuka fase aggregation — salah satu fitur terkuat MongoDB. Roadmap-nya: pertama kita pahami konsep pipeline yang berproses bertahap, kedua kita kuasai stage inti $match dan $project, ketiga $group dengan akumulator, keempat $sort, $limit, $skip, dan terakhir $unwind untuk membuka array. Mari mulai.

Konsep Aggregation Pipeline

Aggregation pipeline bekerja seperti Unix pipes: data mengalir dari satu stage ke stage berikutnya, dan setiap stage mengubah bentuknya. Hasil satu stage menjadi input stage berikutnya. Contoh konsepnya:

Pipeline seperti Unix pipes
db.orders.aggregate([
  { $match: { status: "paid" } },
  { $group: { _id: "$category", total: { $sum: "$total" } } },
  { $sort: { total: -1 } }
])

Baca alurnya: ambil hanya order berstatus paid → kelompokkan per kategori sambil menjumlahkan total → urutkan dari terbesar. Analogi Unix: cat file | grep paid | sort. Kekuatan pipeline: setiap stage bisa digabung secara fleksibel, dan MongoDB mengoptimalkan urutan stage yang aman untuk dipertukarkan.

Fungsi yang dipakai adalah aggregate, dengan array berisi stages. Stage ditulis dalam object, dan field dokumen dirujuk dengan prefiks $ — contoh "$total" merujuk nilai field total pada dokumen yang sedang diproses.

$match: Menyaring Dokumen

$match memfilter dokumen yang masuk ke pipeline — persis seperti find. Inilah stage yang harus ditaruh di awal pipeline karena dua alasan: ia mengurangi jumlah dokumen yang harus diproses stage berikutnya, dan jika memakai field ber-index, MongoDB bisa memulai dari hasil index scan, bukan full scan.

Filter awal dengan $match
db.orders.aggregate([
  { $match: { status: "paid", createdAt: { $gte: ISODate("2026-01-01") } } },
  { $count: "paidOrders2026" }
])

Stage $count menghasilkan satu dokumen berisi jumlah dokumen yang lolos stage sebelumnya — cara cepat menghitung.

$project dan $addFields: Membentuk Ulang Output

$project

$project memilih field mana yang dibawa ke stage berikutnya, mirip projection di find, tapi lebih kaya — ia bisa membuat field komputasi baru:

Projection dengan field baru
db.orders.aggregate([
  { $project: {
      orderId: "$_id",
      total,
      status,
      totalWithTax: { $multiply: ["$total", 1.11] }
  } }
])

Field totalWithTax dihitung saat pipeline berjalan — mengalikan total dengan 1.11 untuk menambahkan pajak 11 persen.

$addFields

$addFields menambah field baru tanpa membuang field lama — kebalikan filosofi $project yang selektif. Ini stage terbaik untuk perhitungan bertahap yang hasilnya dipakai stage berikutnya:

Menambahkan field tanpa menghapus yang lain
db.orders.aggregate([
  { $addFields: {
      year: { $year: "$createdAt" },
      month: { $month: "$createdAt" }
  } },
  { $group: {
      _id: { year: "$year", month: "$month" },
      totalRevenue: { $sum: "$total" }
  } }
])

Contoh ini mengekstrak tahun dan bulan dari createdAt sebagai field baru, lalu mengelompokkan berdasarkan keduanya — fondasi laporan penjualan bulanan.

$group: Mengelompokkan dan Menghitung

$group adalah stage paling transformatif. Ia mengelompokkan dokumen berdasarkan field _id yang ditentukan, lalu menghitung akumulator untuk tiap kelompok. Akumulator yang sering dipakai:

AkumulatorFungsi
$sumMenjumlahkan nilai
$avgRata-rata nilai
$min / $maxNilai terkecil / terbesar
$countMenghitung dokumen per kelompok
$pushMengumpulkan nilai ke array
$addToSetMengumpulkan nilai unik ke array
Grouping lengkap dengan beberapa akumulator
db.orders.aggregate([
  { $group: {
      _id: "$category",
      totalRevenue: { $sum: "$total" },
      averageOrder: { $avg: "$total" },
      maxOrder: { $max: "$total" },
      minOrder: { $min: "$total" },
      orderCount: { $count: {} }
  } }
])

Perhatikan pola $count: {} di dalam $group — menghitung jumlah dokumen per kelompok. Hasilnya adalah ringkasan lengkap per kategori: pendapatan total, rata-rata, maksimum, minimum, dan jumlah order.

$sort, $limit, dan $skip

Sama seperti di find, pipeline mendukung sorting dan pembatasan hasil — berguna untuk menampilkan peringkat atau paginasi:

Sorting dan limit di pipeline
db.products.aggregate([
  { $sort: { soldCount: -1 } },
  { $limit: 5 }
])

Query di atas menghasilkan lima produk terlaris. Pola $sort sebelum $limit adalah teknik penting: MongoDB bisa mengoptimalkannya memakai index untuk menghindari sort penuh.

$unwind: Membuka Array

$unwind memecah setiap dokumen yang berisi array menjadi beberapa dokumen — satu per elemen array. Ini stage krusial saat data ter-embed dalam array dan kalian perlu agregasi per elemen.

Dokumen order dengan items array
{
  "_id": ObjectId("66xxxxxxxxxxxxxxxxxxxxxxxx"),
  "status": "paid",
  "items": [
    { "name": "Laptop Gaming", "price": 15000000, "qty": 1 },
    { "name": "Mouse", "price": 150000, "qty": 2 }
  ]
}
Unwind lalu group per item
db.orders.aggregate([
  { $match: { status: "paid" } },
  { $unwind: "$items" },
  { $group: {
      _id: "$items.name",
      totalSold: { $sum: "$items.qty" },
      revenue: { $sum: { $multiply: ["$items.price", "$items.qty"] } }
  } },
  { $sort: { revenue: -1 } }
])

Tanpa $unwind, $group tidak bisa menjumlahkan per item karena array tertutup dalam dokumen. Setelah $unwind, setiap item jadi dokumen terpisah dan bisa diagregasi — total unit terjual dan pendapatan per produk.

Info

Urutan stage sangat menentukan performa. Aturan praktis: letakkan $match dan $project yang memangkas data di awal pipeline, $unwind sebelum $group jika dibutuhkan, dan $sort/$limit untuk membatasi output. Pipeline yang menyeleksi data lebih dulu jauh lebih cepat daripada yang mengolah semuanya lalu membuang. Gunakan db.collection.explain("executionStats") — yang kita bedah di episode 13 — untuk melihat berapa banyak dokumen melewati tiap stage.

Warning

$unwind bisa menggandakan ukuran pipeline secara drastis: satu dokumen dengan 100 elemen array menjadi 100 dokumen. Jika array-nya raksasa dan kalian hanya butuh ringkasan, pertimbangkan menghitung di sisi aplikasi atau menyimpan data yang sudah diagregasi. Biasakan menempatkan $match sebelum $unwind untuk meminimalkan penggandaan.

Penutup

Pada episode 9 ini kalian telah menguasai fondasi aggregation pipeline: konsep stages berurutan seperti Unix pipes, $match untuk menyaring di awal pipeline, $project dan $addFields untuk membentuk ulang dokumen, $group dengan akumulator $sum, $avg, $count, $push, dan $addToSet, $sort, $limit, $skip untuk menyusun dan membatasi output, serta $unwind untuk membuka array menjadi dokumen individual.

Inti yang harus dibawa pulang:

  • Pipeline mengalirkan data dari stage ke stage; tiap stage mengubah bentuknya.
  • $match di awal pipeline memangkas data dan memanfaatkan index.
  • $group + akumulator adalah jantung agregasi statistik.
  • $unwind membuka array agar bisa diagregasi per elemen.
  • Sortir dengan $sort lalu batasi dengan $limit untuk hasil yang efisien.

Di episode 10 berikutnya kita mendorong aggregation ke level profesional: Advanced Aggregation: Lookups, Facets & Window Functions. Kalian akan menggabungkan data antar collection dengan $lookup, menjalankan beberapa sub-pipeline paralel dengan $facet, mengelompokkan ke bucket dengan $bucket, dan menghitung ranking serta running totals dengan $setWindowFields. Sampai jumpa di episode 10!