Di dunia relational database, kebiasaannya adalah melakukan normalisasi terlebih dahulu — memecah data ke tabel-tabel dan menghapus redundansi — lalu menyusun query belakangan. Document modeling membalik urutan itu: kita mulai dari pertanyaan “data ini akan dibaca dan ditulis bagaimana oleh aplikasi?”, lalu membentuk document mengikuti jawabannya. Chapter ini merangkum prinsip inti dari dokumentasi resmi MongoDB sebelum kita masuk ke teknik pemodelan yang lebih spesifik di chapter-chapter berikutnya.

Empat prinsip yang akan kita pegang sepanjang Section ini:

  • Rancang berdasarkan pola akses, bukan bentuk normal.
  • Data yang selalu diakses bersama, disimpan bersama.
  • Duplikasi boleh, asalkan sadar dan terkendali.
  • Join bukan kewajiban — hindari join pada jalur yang paling sering dipakai.

Rancang Berdasarkan Pola Akses #

Dokumentasi resmi MongoDB menyebutnya lugas: kunci desain data model adalah memahami data apa yang dibutuhkan aplikasi dan bagaimana data itu diakses — bukan meniru struktur tabel yang sudah ada. Dua aplikasi bisa menyimpan entitas yang sama namun membutuhkan skema berbeda karena pola aksesnya berbeda: aplikasi etalase membaca judul dan harga jutaan kali per hari, sedangkan aplikasi moderasi memindai ulasan mentah terus-menerus dan jarang menyentuh harga.

Karena itu, sebelum menulis satu document pun, jawab dulu tabel pertanyaan berikut:

Pertanyaan kunciKenapa pentingDampak pada desain
Berapa rasio baca : tulis?Read-heavy membuat duplikasi dan embed layak; write-heavy membuat update berulang terasa mahalArah embed vs referensi
Query utama apa saja?Field yang selalu difilter butuh posisi strategis dan indexBentuk field, projection, index
Data mana yang selalu diakses bersama?Kandidat kuat untuk disematkan dalam satu documentEmbed
Seberapa cepat data tumbuh?Array yang tumbuh tanpa batas mendekati limit 16 MB per documentCollection terpisah, subset
Seberapa sering data terkait berubah?Data yang sering berubah lebih aman dipelihara di satu tempatReferensi
Seberapa ketat konsistensi antar data terkait?Duplikasi menuntut strategi sinkronisasiDuplikasi sadar

Tabel ini bukan sekadar teori — setiap chapter di Section ini pada dasarnya adalah satu baris tabel itu yang dijabarkan.

Data yang Diakses Bersama, Disimpan Bersama #

Prinsip paling produktif untuk praktik: kalau halaman aplikasi selalu membaca dua data bersamaan, letakkan keduanya dalam satu document. Satu query, satu round trip, tanpa penggabungan di sisi aplikasi. Kita buktikan dengan pola akses yang paling umum di toko buku: halaman detail buku yang menampilkan data buku beserta ulasannya.

Cara pertama meniru gaya relational — dua collection terpisah:

js
use latihan_modeling
db.dropDatabase()
db.buku.insertMany([
  { _id: 101, judul: "Bumi", penulis: "Tere Liye", harga: 89000 },
  { _id: 102, judul: "Laut Bercerita", penulis: "Leila S. Chudori", harga: 98000 }
])
db.ulasan.insertMany([
  { bukuId: 101, pembaca: "Budi", bintang: 4 },
  { bukuId: 101, pembaca: "Siti", bintang: 5 },
  { bukuId: 102, pembaca: "Dewi", bintang: 5 }
])

Output yang Dihasilkan:

text
switched to db latihan_modeling
{ ok: 1, dropped: 'latihan_modeling' }
{ acknowledged: true, insertedIds: { '0': 101, '1': 102 } }
{
  acknowledged: true,
  insertedIds: {
    '0': ObjectId('6ad39847b08a32fa1deb48f6'),
    '1': ObjectId('6ad39847b08a32fa1deb48f7'),
    '2': ObjectId('6ad39847b08a32fa1deb48f8')
  }
}

Untuk merender satu halaman, aplikasi harus menjalankan dua query:

js
db.buku.findOne({ _id: 101 })
db.ulasan.find({ bukuId: 101 })

Output yang Dihasilkan:

text
{ _id: 101, judul: 'Bumi', penulis: 'Tere Liye', harga: 89000 }
[
  {
    _id: ObjectId('6ad39847b08a32fa1deb48f6'),
    bukuId: 101,
    pembaca: 'Budi',
    bintang: 4
  },
  {
    _id: ObjectId('6ad39847b08a32fa1deb48f7'),
    bukuId: 101,
    pembaca: 'Siti',
    bintang: 5
  }
]

Data yang sama, kini disimpan sebagai satu document utuh — ulasan menjadi array di dalam buku:

js
db.buku_embed.insertOne({
  _id: 101,
  judul: "Bumi",
  penulis: "Tere Liye",
  harga: 89000,
  ulasan: [
    { pembaca: "Budi", bintang: 4 },
    { pembaca: "Siti", bintang: 5 }
  ]
})
db.buku_embed.findOne({ _id: 101 })

Output yang Dihasilkan:

text
{ acknowledged: true, insertedId: 101 }
{
  _id: 101,
  judul: 'Bumi',
  penulis: 'Tere Liye',
  harga: 89000,
  ulasan: [ { pembaca: 'Budi', bintang: 4 }, { pembaca: 'Siti', bintang: 5 } ]
}

Bedah perbedaan kedua model:

  1. Jumlah query halaman: model terpisah butuh dua query plus penggabungan di aplikasi; model embed cukup satu findOne.
  2. Field bukuId: pada model terpisah, setiap ulasan membawa bukuId dan _id sendiri — overhead yang berulang di setiap baris; pada model embed, keduanya hilang karena konteksnya sudah dipegang document induk.
  3. Konsekuensi tulis: embed membuat setiap ulasan baru menulis ulang sebagian document buku. Untuk dua ulasan hal ini sepele; untuk dua ribu ulasan ceritanya berbeda — itu bahasan Chapter Embedding vs Referencing.

Duplikasi Sadar, Bukan Normalisasi Buta #

Normalisasi relational memperlakukan duplikasi sebagai cacat yang harus dihapus demi integritas. Document modeling memperlakukan duplikasi sebagai alat tawar: kalau setiap halaman pesanan butuh nama pembeli, menyimpan namaPembeli di dalam document pesanan menghemat satu query per halaman — meskipun nilai yang sama juga tersimpan di collection pengguna.

Konsekuensinya jujur saja tidak nyaman: ketika pembeli mengganti nama, ada dua tempat yang harus diperbarui, dan di antara keduanya data bisa basang (stale). Karena itu aturan mainnya: duplikasikan data yang kecil, sering dibaca, dan jarang berubah. Strategi sinkronisasi lengkapnya kita bahas di Chapter Duplikasi Data.

Join Bukan Kewajiban #

MongoDB menyediakan $lookup untuk operasi mirip join di aggregation pipeline, dan kita akan memakainya di beberapa chapter ke depan. Tetapi $lookup tetap merupakan pekerjaan yang dilakukan saat query berjalan — bukan struktur yang disiapkan di muka seperti foreign key. Pada jalur panas yang dieksekusi ribuan kali per detik, desain yang baik justru menghindari $lookup dengan menyimpan data yang dibutuhkan bersama-sama.

Hal yang sama berlaku untuk penegakan relasi: MongoDB tidak memeriksa bahwa bukuId pada collection ulasan benar-benar menunjuk ke document yang ada. Referensi hanyalah kesepakatan yang dijaga aplikasi — topik yang pernah kita singgung di Section Schema Validation saat membahas bsonType pada field referensi.

Rangkuman #

  • Rancang skema dari pola akses aplikasi: rasio baca-tulis, query utama, pertumbuhan data, dan kebutuhan konsistensi menentukan bentuk document.
  • Data yang selalu dibaca bersama sebaiknya disimpan bersama dalam satu document — satu query untuk satu halaman.
  • Duplikasi adalah pilihan sadar dengan harga sinkronisasi, bukan cacat yang harus dihindari mutlak.
  • $lookup tersedia tetapi bukan struktur bawaan; jalur panas sebaiknya dirancang tanpa join.

Berbekal prinsip-prinsip ini, chapter berikutnya membedah keputusan paling mendasar dalam document modeling: menyematkan data atau merujuknya.