Membedah keputusan terpenting desain data MongoDB: kapan meng-embed dokumen untuk data locality dan kapan mereferensikan dengan ObjectId, memetakan pola one-to-few, one-to-many, dan many-to-many, serta pendekatan hybrid yang menyeimbangkan keduanya.

Di episode 6 kalian mengenal prinsip data locality dan anti-pattern utama. Sekarang kita masuk ke keputusan paling konkret dan paling sering dihadapi arsitek MongoDB: apakah data ini di-embed ke dalam dokumen, atau direferensikan ke collection lain? Ini keputusan yang menentukan performa, konsistensi, dan kompleksitas aplikasi kalian selama bertahun-tahun.
Episode 7 menuntun kalian membuat keputusan ini dengan kerangka berpikir yang jelas. Roadmap-nya: pertama kita pahami model embedded documents (denormalization), kedua referenced documents (normalization), ketiga kita petakan tipe relasi one-to-few, one-to-many, dan many-to-many ke model yang tepat, dan keempat kita gabungkan semuanya dalam pendekatan hybrid. Mari mulai.
Embedding berarti menyimpan data terkait di dalam dokumen yang sama — dalam bentuk embedded document atau array of documents. Ini adalah pendekatan default MongoDB karena selaras dengan prinsip data locality. Satu query membaca seluruh data terkait tanpa JOIN.
Embedding paling cocok untuk hubungan one-to-few: satu dokumen induk dengan beberapa data bawaan yang jumlahnya kecil dan jarang berubah. Contoh klasiknya adalah alamat user:
{
"_id": ObjectId("66xxxxxxxxxxxxxxxxxxxxxxxx"),
"name": "Arman Dwi Pangestu",
"email": "arman@example.com",
"addresses": [
{
"label": "rumah",
"street": "Jl. Merdeka No. 10",
"city": "Jakarta",
"zip": "10110"
},
{
"label": "kantor",
"street": "Jl. Sudirman Kav. 52",
"city": "Jakarta",
"zip": "12190"
}
]
}Keuntungan embedding sangat jelas di sini:
find.Embedding mulai merugikan saat hubungannya one-to-many dengan jumlah besar atau data yang sering di-update sendiri:
Referencing berarti menyimpan relasi menggunakan nilai referensi — biasanya ObjectId — yang menunjuk ke dokumen di collection lain. Data tidak disimpan bersamaan, melainkan dihubungkan secara logis.
Referencing cocok untuk one-to-many dan many-to-many dengan jumlah besar. Contoh klasiknya adalah relasi user dan order — satu user bisa punya ribuan order:
{
"_id": ObjectId("66xxxxxxxxxxxxxxxxxxxxxxxx"),
"userId": ObjectId("66yyyyyyyyyyyyyyyyyyyyyyyy"),
"items": [
{ "productId": ObjectId("66zzzzzzzzzzzzzzzzzzzzzzzz"), "qty": 1 }
],
"total": 150000,
"status": "paid",
"createdAt": ISODate("2026-08-03T10:00:00Z")
}Collection users dan orders terpisah; dokumen order menyimpan userId sebagai referensi. Keuntungannya:
Kelemahannya: membaca order beserta nama user butuh dua query (atau satu $lookup di aggregation — yang kita pelajari di episode 10).
Hubungan induk dengan beberapa item kecil yang melekat (alamat, tag, preferensi). Contoh: user dan address, post dan tags.
Ada dua variasi:
reviewIds. Cocok jika perlu tahu relasi dari sisi induk dan jumlahnya masuk akal.userId. Cocok untuk jumlah besar karena array di induk tidak membengkak. Ini pola paling umum.{
"_id": ObjectId("66xxxxxxxxxxxxxxxxxxxxxxxx"),
"productId": ObjectId("66zzzzzzzzzzzzzzzzzzzzzzzz"),
"rating": 5,
"text": "Produk sangat bagus",
"userId": ObjectId("66yyyyyyyyyyyyyyyyyyyyyyyy")
}Keduanya saling mereferensikan. Contoh: buku dan penulis — satu buku banyak penulis, satu penulis banyak buku. Simpan array authorIds di dokumen buku, atau bookIds di dokumen penulis, atau keduanya.
db.books.find({ authorIds: ObjectId("66yyyyyyyyyyyyyyyyyyyyyyyy") })Dalam praktik nyata, desain terbaik hampir selalu hybrid: menggabungkan embedding dan referencing berdasarkan access pattern spesifik. Dua pola hybrid yang paling umum:
Simpan referensi untuk data kanonik, tapi salin beberapa field penting ke dokumen anak sebagai "snapshot". Contoh paling populer: order menyimpan productId (referensi) sekaligus menyalin productName dan priceAtPurchase (snapshot). Jika harga produk naik di masa depan, order lama tetap mencatat harga saat pembelian — dan daftar order bisa ditampilkan tanpa $lookup ke katalog.
{
"_id": ObjectId("66xxxxxxxxxxxxxxxxxxxxxxxx"),
"items": [
{
"productId": ObjectId("66zzzzzzzzzzzzzzzzzzzzzzzz"),
"name": "Laptop Gaming",
"priceAtPurchase": 15000000,
"qty": 1
}
]
}Untuk data time-series atau log yang sangat sering ditulis, gabungkan banyak record kecil ke dalam satu dokumen "bucket" berkapasitas tetap. Misal menyimpan pengukuran IoT per jam dalam satu dokumen per jam, berisi array 60 menit. Jumlah dokumen menyusut drastis dan query rentang waktu jadi cepat.
Info
Kerangka keputusan cepat: tanyakan dua hal. Pertama, "apakah data ini selalu dibaca bersama dokumen induk?" Jika ya dan kecil → embed. Kedua, "apakah data ini tumbuh tanpa batas atau sering berubah?" Jika ya → referensikan. Jika jawabannya campur → gunakan hybrid dengan snapshot. Tidak ada jawaban salah total, hanya keputusan yang sesuai atau tidak sesuai dengan access pattern.
Warning
Saat meng-embed, pikirkan batas 16 MB ukuran maksimum dokumen (BSON). Dokumen yang membengkak — karena array besar, snapshot berlebihan, atau data historis menumpuk — akan bermasalah saat melewati batas itu. Desain dengan asumsi dokumen tetap ramping; data yang tumbuh tanpa henti selalu lebih baik dipindahkan ke collection terpisah.
Pada episode 7 ini kalian telah memahami dua model relasi di MongoDB. Embedded documents menyimpan data terkait dalam satu dokumen — sempurna untuk one-to-few seperti alamat user, dengan keuntungan satu query dan data locality. Referenced documents memisahkan data ke collection sendiri dengan referensi ObjectId — tepat untuk one-to-many besar dan many-to-many, dengan keuntungan tanpa duplikasi dan dokumen ramping. Dan pendekatan hybrid menggabungkan keduanya, memakai referensi untuk data kanonik plus snapshot untuk pembacaan cepat.
Inti yang harus dibawa pulang:
Di episode 8 berikutnya kita membuat desain schema menjadi nyata dan terjaga: Schema Validation & Data Integrity Rules. Kalian akan menggunakan $jsonSchema untuk mendefinisikan aturan validasi pada collection, memahami validation level strict versus moderate, serta validation action error versus warn. Sampai jumpa di episode 8!