Belajar MongoDB - Studi Kasus Production-Grade E-Commerce Document Database
Episode 20 of 21

Belajar MongoDB - Studi Kasus Production-Grade E-Commerce Document Database

Merangkai seluruh materi series dalam studi kasus e-commerce: merancang schema users, product catalog, orders, dan analytics; membangun deployment dengan replica set, TLS, backup, dan monitoring; serta meninjau checklist kesiapan produksi sebagai penutup seri.

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

Pendahuluan

Selamat — kalian telah menempuh 19 episode, dari setup, CRUD, query lanjutan, schema design, aggregation, indexing, transaction, replica set, sharding, security, backup, hingga monitoring. Kini tiba saatnya bukti akhir: merangkai semuanya menjadi satu arsitektur production-grade. Episode 20 adalah studi kasus e-commerce yang menyatukan seluruh pengetahuan: merancang schema users & auth, product catalog, orders & inventory, dan analytics, lalu deployment architecture dengan replica set, TLS, backup, dan monitoring, ditutup checklist kesiapan produksi dan refleksi akhir.

Users & Auth

Schema User dengan Embedded Addresses

User memegang profil dan daftar alamat. Karena jumlah alamat per user kecil dan selalu dibaca bersama profil, kita embed alamat sebagai array (pola one-to-few dari episode 7):

Dokumen user dengan embedded addresses
{
  "_id": ObjectId("66aaaaaaaaaaaaaaaaaaaaaaaa"),
  "email": "siti@example.com",
  "name": "Siti Rahma",
  "role": "customer",
  "status": "active",
  "nationalIdEncrypted": BinData(0, "...ciphertext..."),
  "addresses": [
    { "label": "rumah", "street": "Jl. Merdeka No. 10", "city": "Jakarta", "zip": "10110" }
  ],
  "createdAt": ISODate("2026-01-15T09:00:00Z")
}

Perhatikan nationalIdEncrypted — NIK disimpan sebagai ciphertext hasil CSFLE (episode 17): dienkripsi di sisi aplikasi, sehingga server pun tidak bisa membacanya.

Proteksi Data User

  • Index unik pada email — menjamin tidak ada duplikat akun di level database.
  • SCRAM-SHA-256 untuk autentikasi user aplikasi; custom roles membatasi hak tiap service (service auth punya write, service billing hanya read).
  • Partial index { email: 1 } pada dokumen status: "active" — user yang di-soft-delete tidak mengunci emailnya.
Index untuk collection users
db.users.createIndex({ email: 1 }, { unique: true })
db.users.createIndex({ email: 1 }, { unique: true, partialFilterExpression: { status: "active" } })

Product Catalog

Flexible Schema untuk Atribut Dinamis

Produk punya atribut yang sangat beragam: fashion punya size dan color, elektronik punya specs. Ini pekerjaan sempurna untuk flexible schema — atribut dinamis disimpan sebagai embedded document (episode 7), sehingga tiap kategori bebas menentukan strukturnya:

Dokumen produk dengan atribut dinamis
{
  "_id": ObjectId("66bbbbbbbbbbbbbbbbbbbbbbbb"),
  "name": "Laptop Gaming 15",
  "category": "elektronik",
  "price": NumberDecimal("15000000"),
  "stock": 5,
  "tags": ["best-seller", "baru"],
  "specs": { "ram": "16GB", "storage": "512GB SSD" }
}

Index untuk Pencarian dan Lelang Flash

Index untuk katalog produk
db.products.createIndex({ category: 1, price: 1 })
db.products.createIndex({ name: "text", description: "text" })
db.flashSales.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })
  • Compound index { category: 1, price: 1 } — mengikuti aturan ESR (episode 12) untuk query "produk elektronik dengan harga tertentu" yang paling sering dijalankan.
  • Text index — full-text search nama dan deskripsi (episode 11).
  • TTL index pada collection flashSales — dokumen promo lelang otomatis dihapus setelah satu jam, tanpa cron job manual.

Orders & Inventory

Konsistensi Stok dengan Transaksi

Membuat order sambil mengurangi stok harus atomik — jika stok terpotong tapi order gagal, atau sebaliknya, toko kalian kacau. Solusinya: multi-document ACID transaction (episode 14):

JSBuat order dan kurangi stok secara atomik (Node.js)
const session = client.startSession();
session.startTransaction();
try {
  await products.updateOne({ _id: productId, stock: { $gte: qty } }, { $inc: { stock: -qty } }, { session });
  await orders.insertOne(
    { userId, items: [{ productId, qty, priceAtPurchase }], total, status: "pending", createdAt: new Date() },
    { session }
  );
  await session.commitTransaction();
} catch (err) {
  await session.abortTransaction();
} finally {
  await session.endSession();
}

Dua detail cerdas: filter stock: { $gte: qty } memastikan pengurangan stok hanya terjadi jika persediaan mencukupi (jika tidak, transaksi di-abort), dan priceAtPurchase adalah snapshot harga (episode 7) — order tetap mencatat harga saat pembelian meski harga berubah nanti.

Notifikasi Real-time dengan Change Streams

Setelah order dibuat, statusnya berubah-ubah: pending, paid, shipped, delivered. Untuk memberi tahu user secara real-time, kita pasang change stream (episode 18) pada collection orders:

JSChange stream untuk notifikasi status order
const changeStream = orders.watch([
  { $match: { operationType: "update", "updateDescription.updatedFields.status": { $exists: true } } }
]);
changeStream.on("change", (event) => {
  notifyUser(event.documentKey._id, event.updateDescription.updatedFields.status);
});

Setiap status order berubah, aplikasi mengirim notifikasi ke user — tanpa polling, hampir tanpa latensi. Ini juga sumber data untuk pipeline sinkronisasi ke search engine atau data warehouse.

Analytics

Agregasi untuk Laporan Harian

Dengan aggregation pipeline (episode 9 dan 10), kebutuhan analitik dipenuhi dalam query terpusat. Laporan penjualan harian per kategori:

Penjualan harian per kategori
db.orders.aggregate([
  { $match: { status: "paid" } },
  { $unwind: "$items" },
  { $addFields: { day: { $dateToString: { format: "%Y-%m-%d", date: "$createdAt" } } } },
  { $group: { _id: { day: "$day", category: "$items.category" }, revenue: { $sum: { $multiply: ["$items.priceAtPurchase", "$items.qty"] } } } },
  { $sort: { "_id.day": 1 } }
])

Dashboard dalam Satu Query dengan $facet

Halaman dashboard butuh beberapa ringkasan sekaligus — total revenue, produk terlaris, dan order terbaru. $facet menjalankannya dalam satu query yang konsisten:

Ringkasan dashboard dengan facet
db.orders.aggregate([
  { $match: { status: "paid" } },
  { $facet: {
      "summary": [{ $group: { _id: null, totalRevenue: { $sum: "$total" } } }],
      "topProducts": [{ $unwind: "$items" }, { $group: { _id: "$items.productId", qty: { $sum: "$items.qty" } } }, { $sort: { qty: -1 } }, { $limit: 10 }],
      "recent": [{ $sort: { createdAt: -1 } }, { $limit: 5 }]
  } }
])

Deployment Architecture

Blueprint arsitektur deployment e-commerce
3-Member Replica Set (rs0): Primary tulis + baca, Secondary baca untuk laporan + kandidat failover
Lapisan keamanan: SCRAM-SHA-256 untuk semua user, RBAC role per service, TLS semua koneksi, CSFLE field sensitif
Otomasi operasional: mongodump tiap 6 jam + uji restore bulanan, Prometheus/Grafana + alerting, profiler slowms 100

Checklist Kesiapan Produksi

  • Autentikasi aktif (authorization: enabled) dan tidak ada user default.
  • RBAC minimal: aplikasi tidak berjalan sebagai root.
  • TLS aktif untuk semua koneksi dan antar node.
  • Backup otomatis terjadwal dan uji restore sudah terbukti berhasil.
  • Monitoring dengan alert untuk CPU, memory, connection, dan replication lag.
  • Index sudah memakai explain() untuk memverifikasi IXSCAN pada query utama.
  • Validation schema aktif untuk collection penting.
  • Maintenance window dijadwalkan untuk compact/reIndex rutin.
  • Rencana failover teruji (replica set) dan skenario restore didokumentasikan.

Penutup

Selamat — kalian telah menempuh seluruh perjalanan Belajar MongoDB dari nol hingga production-grade. Di episode penutup ini kalian merangkai semuanya: schema users dengan embedded addresses dan CSFLE, product catalog dengan flexible attributes dan compound plus TTL index, order & inventory dengan ACID transaction dan change streams, serta analytics dengan aggregation pipeline dan $facet. Kalian juga menyusun deployment replica set tiga anggota dengan TLS, backup otomatis, dan monitoring Prometheus/Grafana, plus checklist kesiapan produksi yang siap pakai.

Inti yang harus dibawa pulang:

  • Schema yang baik mengikuti access pattern: embed yang dibaca bersama, referensikan yang besar.
  • Konsistensi stok dan order dijamin dengan multi-document transaction.
  • Change streams mengubah database menjadi sumber event real-time.
  • Satu query aggregation bisa menggantikan puluhan panggilan terpisah.
  • Deployment produksi = replica set + TLS + RBAC + backup teruji + monitoring.
  • Flexible schema bukan alasan untuk malas merancang — justru alasan untuk lebih disiplin.

Terima kasih sudah bertahan sampai akhir. Kalian bukan lagi sekadar "tahu MongoDB" — kalian punya kerangka berpikir yang utuh: dari cara menulis query, merancang schema, mengamankan, memantau, hingga membangun sistem produksi. Sekarang saatnya membawa pengetahuan ini ke proyek kalian sendiri. Mulailah kecil, verifikasi dengan explain(), dan jadikan setiap keputusan didasari data — persis seperti yang kalian pelajari di seluruh seri ini. Selamat berkarya!

Belajar MongoDB - Studi Kasus Production-Grade E-Commerce Document Database | Belajar MongoDB