Apa itu Dokumen

Dokumen ternyata tidak sesederhana kelihatannya. Contoh: dokumen HTML sederhana berisi dua jenis informasi — content (teks dan referensi ke gambar/audio/media lain) dan formatting command (tag HTML yang menentukan tampilan). Pada document database, yang dipakai adalah struktur yang memisahkan content dari formatting, biasanya lewat JSON atau XML.

Contoh JSON

{
  "customer_id": 187693,
  "name": "Kiera Brown",
  "address": {
    "street": "1232 Sandy Blvd.",
    "city": "Vancouver",
    "state": "Washington",
    "zip": "99121"
  },
  "first_order": "01/15/2013",
  "last_order": "06/27/2014"
}

Aturan sintaks JSON:

  • Data diorganisasikan dalam pasangan key-value, mirip key-value database.
  • Dokumen terdiri dari pasangan nama-nilai dipisah koma, diapit { dan }.
  • Nama berupa string, mis. "customer_id", "address".
  • Nilai bisa berupa: angka, string, boolean (true/false), array, objek, atau null.
  • Nilai array diapit [ dan ]; nilai objek berupa pasangan key-value diapit { dan } (bisa bersarang).

JSON hanyalah salah satu opsi merepresentasikan dokumen — opsi lain adalah XML:

<customer_record>
  <customer_id>187693</customer_id>
  <name>Kiera Brown</name>
  <address>
    <street>1232 Sandy Blvd.</street>
    <city>Vancouver</city>
    <state>Washington</state>
    <zip>99121</zip>
  </address>
  <first_order>01/15/2013</first_order>
  <last_order>06/27/2014</last_order>
</customer_record>

Dokumen vs Key-Value Pair

Keunggulan dokumen dibanding key-value database murni: atribut-atribut terkait dikelola dalam satu objek. Dokumen, seperti tabel relasional, mengorganisasikan banyak atribut dalam satu objek — lebih mudah memenuhi kebutuhan umum seperti mengembalikan seluruh atribut suatu entitas berdasarkan filter pada salah satu atributnya. Pada key-value database murni, kebutuhan serupa memerlukan query terpisah ke tiap key individual.

Mengelola Banyak Koleksi Dokumen

Dokumen umumnya dikelompokkan ke dalam collection dokumen sejenis — collection bisa dibayangkan sebagai list of documents. Desainer document database mengoptimalkan basis data untuk cepat menambah, menghapus, memperbarui, dan mencari dokumen. Penting dicatat: dokumen dalam satu collection tidak wajib punya struktur identik, tapi sebaiknya berbagi sebagian struktur umum. Contoh: dua dokumen customer pertama punya struktur sama, sedangkan dokumen ketiga & keempat punya field tambahan (loyalty_level, large_purchase_discount, large_purchase_amount, dst.) — semuanya tetap valid dalam satu collection yang sama.

Document and Collection Terms

Lima istilah kunci: document, collection, embedded document, schemaless, polymorphic schema.

Document

Document adalah sekumpulan pasangan key-value yang terurut (ordered). Key umumnya berupa string; value bisa berbagai tipe data: angka, string, array, dsb. Value juga bisa berupa dokumen lain yang di-embed — mis. field pastProjects pada dokumen employee berisi array dokumen proyek (masing-masing dengan projectCode, projectName, projectManager) yang disimpan langsung di dalam dokumen employee.

Collection

Collection adalah kumpulan dokumen — umumnya berkaitan dengan entitas subjek yang sama (mis. employee, product, logged event, customer profile). Collection memungkinkan operasi terhadap grup dokumen terkait secara efisien, didukung struktur data tambahan seperti index (memetakan atribut, mis. key terms, ke informasi terkait seperti lokasi data — analog indeks buku yang jauh lebih cepat dibanding memindai seluruh isi buku untuk mencari suatu istilah).

Embedded Document

Embedded document memungkinkan pengguna document database menyimpan data terkait dalam satu dokumen — sehingga menghindari proses joining (yang diperlukan pada model relasional karena data entitas berbeda dipisah ke tabel berbeda). Embedded document adalah dokumen di dalam dokumen, dipakai untuk menyimpan dan mengambil data yang sering dipakai bersama secara efisien.

Schemaless

Document database tidak mewajibkan data modeler secara formal menspesifikasikan struktur dokumen (schema) — berbeda dari relational database yang mewajibkan schema eksplisit sebelum data bisa dimasukkan.

  • Schemaless berarti lebih fleksibel: developer dan aplikasi bisa menambahkan pasangan key-value baru ke dokumen kapan saja.
  • Schemaless berarti lebih banyak tanggung jawab: document database management tidak bisa menegakkan aturan berbasis struktur — aturan (validasi field wajib, rentang nilai valid, referensi objek yang ada, dst.) harus ditegakkan lewat kode aplikasi. Pengecualian: penggunaan unique identifier tetap ditegakkan sistem.

Meski schemaless (bebas dari kewajiban mendefinisikan struktur basis data di muka), tetap ada organisasi implisit dalam set dokumen yang disisipkan — organisasi ini tercermin dari kode yang memanipulasi dokumen tersebut. Ini melahirkan konsep polymorphic schema.

Polymorphic Schema

Polymorphic berasal dari bahasa Latin, artinya “banyak bentuk”. Document database bersifat polymorphic karena dokumen yang ada dalam satu collection bisa punya banyak bentuk berbeda. Schemaless berarti tidak ada definisi struktur formal; polymorphic schema berarti ada banyak struktur dokumen implisit yang muncul dalam set dokumen suatu collection (mis. tiga dokumen dalam satu collection, masing-masing punya kombinasi field berbeda: {a,b,c}, {a,b,d}, {a,e,f,g}).

Basic Operations on Document Databases

Empat operasi dasar: inserting, deleting, updating, retrieving. Basis data adalah container untuk collection, dan collection adalah container untuk dokumen. Tidak ada satu bahasa manipulasi data standar yang dipakai lintas document database — contoh berikut memakai sintaks MongoDB.

Inserting:

db.books.insert({"title": "Mother Night", "author": "Kurt Vonnegut, Jr."})
db.books.insert({book_id: 1298747, "title": "Mother Night", "author": "Kurt Vonnegut, Jr."})
db.books.insert([
  {"book_id": 1298747, "title": "Mother Night", "author": "Kurt Vonnegut, Jr."},
  {"book_id": 639397, "title": "Science and the Modern World", "author": "Alfred North Whitehead"},
  {"book_id": 1456701, "title": "Foundation and Empire", "author": "Isaac Asimov"}
])

Deleting:

db.books.remove()
db.books.remove({"book_id": 639397})
db.books.remove({"author": "Kurt Vonnegut, Jr."})

Updating — method update butuh dua parameter: query dokumen, dan set key-value yang di-update:

db.books.update({"book_id": 1298747}, {$set: {"quantity": 10}})
db.books.update({"book_id": 1298747}, {$inc: {"quantity": 5}})

Retrieving — method find:

db.books.find()
db.books.find({"author": "Kurt Vonnegut, Jr."})
db.books.find({"author": "Kurt Vonnegut, Jr."}, {"title": 1})
db.books.find({"quantity": {"$gte": 10, "$lt": 50}})

Conditional/boolean operator yang didukung MongoDB: $lt (less than), $lte (less than or equal), $gt (greater than), $gte (greater than or equal), $in (query nilai pada satu key), $or (query nilai lintas banyak key), $not (negasi).

Designing Document Based Database

Fase Desain NoSQL Document Database

Menurut Rossel & Manna (2020), desain document database melewati tiga fase:

  1. High level: mengembangkan conceptual model (mis. lewat ER modeling, lihat ER Modeling), sekaligus menspesifikasikan query pattern dari analisis kebutuhan.
  2. Logical level: menetapkan tipe-tipe dokumen dan interelasinya — direpresentasikan lewat Document Interaction Diagram (DID); tiap tipe dokumen dispesifikasikan memakai JSON Schema.
  3. Physical level: analisis dan optimasi model logis — mencakup pembuatan index, sharding, distribusi data, dan penyesuaian tipe data ke software basis data spesifik.

Normalization

Normalization adalah proses mengorganisasikan data ke dalam tabel sedemikian rupa untuk mengurangi potensi anomali data (inkonsistensi data) — sudah dibahas mendalam di materi basis data relasional sebelumnya. Terkadang performa relational database justru buruk karena model yang ternormalisasi (banyak join diperlukan).

Kebutuhan join: untuk membuat laporan yang menyertakan atribut dari dua tabel atau lebih, diperlukan join — tabel yang di-join harus berbagi nilai yang sama, dikenal sebagai foreign key.

Eksekusi join adalah pekerjaan berat relational database. Contoh algoritma dasar nested loop join untuk menghitung theta join r ⨝θ s:

for each tuple tr in r do begin
  for each tuple ts in s do begin
    test pair (tr, ts) untuk melihat apakah memenuhi kondisi join θ
    jika ya, tambahkan tr · ts ke hasil
  end
end

Nested loop join mahal karena memeriksa setiap pasangan tuple dari kedua relasi. Alternatif: indexed nested loop join, merge-join, hash-join. Query optimizer DBMS berusaha mencari cara terbaik mengambil dan menggabungkan data, tapi eksekusi join pada dataset besar tetap bisa memakan waktu dan resource signifikan.

Denormalization

Denormalization membalikkan normalisasi — secara spesifik, memperkenalkan redundansi data secara sengaja. Alasan mengambil risiko anomali data dan tambahan storage: denormalisasi bisa meningkatkan performa query secara signifikan — saat data didenormalisasi, tidak perlu membaca data dari banyak tabel dan melakukan join.

“Denormalization” pada document database: bandingkan dua desain berikut untuk mencatat item pesanan beserta info produk:

Dua collection terpisah (butuh dua lookup):

// Order document
{"order_item_ID": 834838, "order_ID": 8827, "quantity": 3, "cost_per_unit": 8.50, "product_ID": 3648}
// Product document
{"product_ID": 3648, "product_description": "...", "product_name": "Eco-friendly Printer Paper",
 "product_category": "office supplies", "list_price": 9.00}

Didenormalisasi — embed product langsung di order item (satu lookup saja):

{
  "order_item_ID": 834838, "order_ID": 8827, "quantity": 3, "cost_per_unit": 8.50,
  "product": {
    "product_description": "1 package laser printer paper. 100% recycled.",
    "product_name": "Eco-friendly Printer Paper",
    "product_category": "office supplies",
    "list_price": 9.00
  }
}

Perhatikan: field product_ID (yang berfungsi sebagai database reference/foreign key) tidak lagi diperlukan pada versi yang di-embed.

Embedding vs Referencing

Embedded documentReferenced document
StrukturDokumen disimpan di dalam dokumen lain, membentuk struktur nested/hierarkisRelasi disimpan lewat referensi (biasanya ObjectId) ke dokumen lain di collection berbeda
Use case idealOne-to-one (mis. profil user & pengaturan user); one-to-many dengan child tidak terlalu besar (mis. komentar di bawah satu post blog)Many-to-many (mis. mahasiswa mendaftar banyak kelas, kelas punya banyak mahasiswa); subdokumen besar yang diakses independen (mis. review produk di collection terpisah)

Modeling one-to-many relations: contoh — satu order punya banyak order item, satu gedung apartemen punya banyak unit apartemen, satu organisasi punya banyak departemen. Pola dasar: entity di sisi “one” menjadi dokumen utama (primary document), entity di sisi “many” direpresentasikan sebagai array embedded document:

{
  "customer_id": 76123, "name": "Acme Data Modeling Services", "person_or_business": "business",
  "address": [
    {"street": "276 North Amber St", "city": "Vancouver", "state": "WA", "zip": 99076},
    {"street": "89 Morton St", "city": "Salem", "state": "NH", "zip": 1097}
  ]
}

Modeling many-to-many relations: contoh — dokter punya banyak pasien & pasien punya banyak dokter; mahasiswa terdaftar di banyak kelas & kelas punya banyak mahasiswa. Dimodelkan lewat dua collection, masing-masing menyimpan list identifier yang mereferensikan entitas terkait di collection lain (bukan embedded document penuh) — pola ini meminimalkan duplikasi data:

// Collection Courses
{"courseID": "C1667", "title": "Introduction to Anthropology", "instructor": "Dr. Margret Austin",
 "credits": 3, "enrolledStudents": ["S1837", "S3737", "S9825", "..."]}
// Collection Students
{"studentID": "S1837", "name": "Brian Nelson", "gradYear": 2018, "courses": ["C1667", "C2873", "C3876"]}

Faktor yang perlu dipertimbangkan saat memilih embedding vs referencing:

  1. Access pattern: data yang sering diakses bersama lebih efisien di-embed; data yang diakses independen/jarang lebih baik direferensikan.
  2. Ukuran & pertumbuhan data: dataset kecil/tetap cocok di-embed; dataset besar/terus bertambah lebih baik direferensikan agar ukuran dokumen tetap terkendali.
  3. Frekuensi update: embedding ideal jika butuh update atomik atas data terkait; referencing lebih baik jika bagian-bagian data di-update sering & independen.
  4. Kompleksitas skema: model data sederhana & hierarkis diuntungkan oleh embedding; relasi kompleks & terus berevolusi lebih baik dikelola lewat referencing.

Hindari denormalisasi berlebihan: dokumen besar menyebabkan lebih sedikit dokumen yang terambil per pembacaan blok data dari persistent storage — ini bisa meningkatkan total jumlah pembacaan blok data untuk mengambil satu collection/subset collection. Contoh strategi seimbang: hanya menduplikasi product_name saja di collection Order_Items (bukan seluruh detail produk) — memakai sedikit lebih banyak storage, tapi memungkinkan mayoritas query diselesaikan dalam satu lookup.

Jangan hindari join secara mutlak: jika kebutuhan aplikasi memang lebih optimal memakai dua/lebih collection terpisah, join tetap bisa diimplementasikan di kode aplikasi:

for doc1 in collection1:
    for doc2 in collection2:
        # lakukan sesuatu dengan kedua dokumen

Kesimpulan: normalisasi berguna mengurangi risiko anomali data; denormalisasi dipakai meningkatkan performa query. Pada document database, data modeler & developer sering memakai denormalisasi — tapi gunakan query sebagai panduan untuk menyeimbangkan normalisasi dan denormalisasi. Normalisasi berlebihan → butuh banyak join; denormalisasi berlebihan → dokumen besar yang menyebabkan pembacaan data tak perlu dari persistent storage.

Planning for Mutable Documents

Sebagian dokumen berubah sering, sebagian jarang. Saat mendesain document database, pertimbangkan bukan hanya seberapa sering dokumen berubah, tapi juga bagaimana ukuran dokumen berubah seiring waktu.

Contoh — fleet management: truk perusahaan mengirim data lokasi, konsumsi bahan bakar, dan metrik operasional lain tiap tiga menit ke basis data manajemen armada. Dua opsi desain:

  • Opsi 1 — dokumen baru per set data: tiap pengiriman data menjadi dokumen baru. Dengan 20 set data/jam × 10 jam operasi = 200 dokumen/hari per truk, field truck_id, date, driver_name terduplikasi di 200 dokumen tersebut.
  • Opsi 2 — embed data operasional dalam satu dokumen truk-per-hari: satu dokumen per truk per hari, dengan array operational_data yang bertambah tiap tiga menit — dimulai dari satu entri, berakhir dengan 200 entri di akhir shift.

Diskusi Opsi 2: dari sisi logical model, ini desain yang baik-baik saja. Namun dari sisi physical model ada potensi masalah performa: ketika dokumen tumbuh melampaui ruang yang dialokasikan untuknya, dokumen bisa dipindahkan (moved) ke lokasi lain — ini membebani sistem storage tambahan dan berpotensi merugikan performa.

Menghindari pemindahan dokumen berukuran besar: alokasikan ruang yang cukup sejak dokumen dibuat. Untuk kasus truk, dokumen bisa dibuat langsung dengan array 200 embedded document (dengan field time dan lainnya diisi nilai default) alih-alih membiarkan array bertambah organik satu per satu.

Index

Index: aplikasi read-heavy (persentase operasi baca tinggi dibanding tulis, mis. business intelligence & aplikasi analitik) — sebaiknya punya index pada hampir seluruh field yang dipakai memfilter hasil, karena query analitik bersifat iteratif dan hampir semua field berpotensi dipakai memfilter.

Index: aplikasi write-heavy (persentase tulis tinggi relatif terhadap baca) — karena index adalah struktur data yang harus dibuat & di-update, penggunaannya mengonsumsi CPU, persistent storage, dan memori, serta menambah waktu insert/update dokumen.

Solusi ketika keduanya harus didukung: memakai dua basis data terpisah — satu document DB dituning untuk writes (transaction database), satu lagi dituning untuk reads (analytics database) — dihubungkan lewat proses Extraction, Transformation, and Load (ETL).

Modeling Hierarchies in Document Databases

Hierarchy mendeskripsikan instance entitas dalam relasi parent-child atau part-subpart — mis. hierarki Product_Categories → Office Furniture/Office Supplies/Electronics → subkategori lebih spesifik seperti Writing Instruments → Pens/Pencils.

Pola 1 — Parent or Child References:

  • Referensi ke parent — tiap dokumen menyimpan parentID yang mereferensikan kategori induknya langsung. Berguna jika sering perlu menampilkan satu instance spesifik lalu menampilkan kategori yang lebih umum di atasnya.
    {"productCategoryID": "PC233", "name": "Pencils", "parentID": "PC72"}
    {"productCategoryID": "PC72", "name": "Writing Instruments", "parentID": "PC37"}
  • Referensi ke children — tiap dokumen menyimpan childrenIDs (array ID anak-anaknya). Berguna jika sering perlu mengambil anak/subpart dari instance yang dimodelkan dalam dokumen tersebut.
    {"productCategoryID": "PC37", "name": "Office Supplies", "childrenIDs": ["PC72", "PC73", "PC74"]}

Pola 2 — Listing All Ancestors: menyimpan seluruh rantai leluhur (ancestor) dalam satu array pada dokumen, mis. {"productCategoryID": "PC233", "name": "Pencils", "ancestors": ["PC72", "PC37", "P01"]}. Berguna saat sering butuh tahu jalur penuh dari suatu titik hierarki kembali ke root.

  • Kelebihan: bisa mengambil jalur penuh ke root dalam satu operasi baca.
  • Kekurangan: perubahan pada hierarki (mis. kategori dipindah) bisa memerlukan banyak operasi tulis (semua descendant yang mereferensikan node tersebut di array ancestors-nya perlu diperbarui).

Menghindari Entity Type yang Terlalu Abstrak

Tip: jika kamu memakai field doc_type dan sering memfilter collection untuk memilih satu tipe dokumen tertentu, tinjau kembali dokumenmu — mungkin sebenarnya kamu mencampur beberapa tipe entitas berbeda dalam satu collection (mis. click_stream dan server_log dicampur dalam collection yang sama, dibedakan lewat doc_type).

Memfilter collection umumnya lebih lambat dibanding bekerja langsung dengan banyak collection yang masing-masing hanya berisi satu tipe dokumen — meski index membantu performa, index bisa di-cache di memori atau disimpan di disk, dan mencampur tipe dokumen dapat menyebabkan beberapa tipe dokumen tercampur dalam satu blok data disk — menimbulkan inefisiensi karena data terbaca dari disk tapi tidak dipakai aplikasi yang memfilter berdasarkan tipe.

Tip lain: jika kode level tertinggi berisi banyak if statement yang mengecek doc_type lalu bercabang ke fungsi terpisah untuk memanipulasi tiap tipe dokumen, ini indikasi kuat kamu perlu memisahkan tipe dokumen tersebut ke collection terpisah. Branching pada level rendah (mis. menangani atribut opsional) itu wajar dan bukan indikasi masalah yang sama.

Namun, gunakan prinsip desain secara fleksibel — pertimbangkan manfaat dan kerugiannya untuk tiap situasi spesifik. Gunakan subtipe dokumen (mencampur beberapa entitas terkait dalam satu collection) ketika entitas-entitas tersebut sering diagregasi bersama atau berbagi banyak kode pemrosesan yang sama. Contoh: entitas Products (dengan atribut umum: nama, deskripsi, SKU, dimensi, berat pengiriman, skor review, harga) punya subtipe Books (author, publisher, tahun terbit, jumlah halaman), CD (artis, produser, jumlah track), dan Small kitchen appliances (warna, voltase, gaya) — jika query yang perlu dijawab (rata-rata jumlah produk dibeli tiap customer, produk terpopuler per state, dsb.) memperlakukan ketiga subtipe tersebut sebagai satu entitas Products, maka menyatukannya dalam satu collection Products lebih tepat dibanding memisah jadi tiga collection. Intinya: query-lah yang memandu organisasi dokumen dan collection, bukan sekadar taksonomi konseptual di atas kertas.

Case Study: Customer Manifest

Konteks: TransGlobal Transport and Shipping (TGTS) mengoordinasikan pengiriman barang. Tiap kontainer memerlukan field inti: nama customer, fasilitas asal & tujuan, ringkasan isi, jumlah item, indikator bahan berbahaya (hazardous material), tanggal kedaluwarsa untuk barang mudah rusak, dan titik kontak pengiriman.

Sebagian kontainer butuh informasi khusus: bahan berbahaya wajib disertai Material Safety Data Sheet (MSDS) untuk penanganan darurat; makanan mudah rusak wajib disertai detail inspeksi makanan (nama inspektur, agensi, kontak agensi).

Analisis pola query: 70–80% query mengembalikan satu record manifest — dicari lewat manifest identifier, atau kombinasi nama customer + tanggal pengiriman + fasilitas asal. Sisanya (20–30%) mayoritas laporan ringkasan per customer atas subset informasi umum; laporan ringkasan per tipe shipment (hazardous, perishable) jarang dibutuhkan manajer.

Keputusan embed vs tidak: field data makanan mudah rusak (perishable foods) ternyata rutin dilaporkan bersama field umum manifest → di-embed langsung dalam dokumen manifest. Sebaliknya, informasi MSDS tidak pernah muncul di laporan sampel yang ditinjau — hanya dibutuhkan facility manager saat keadaan darurat (jarang diakses) → disimpan di collection terpisah, dengan field msdsID pada dokumen manifest yang mereferensikan dokumen MSDS terkait.

Memilih index: karena mayoritas baca adalah pencarian satu manifest, manifest identifier menjadi pilihan index utama. Analis awalnya mempertimbangkan tiga index terpisah untuk nama customer, tanggal pengiriman, dan fasilitas asal — namun karena jarang perlu melist seluruh shipment hanya berdasar tanggal atau fasilitas asal saja, mereka memilih membuat satu index gabungan atas ketiga field tersebut (nama customer, tanggal pengiriman, fasilitas asal) alih-alih tiga index terpisah.

Collection terpisah per tipe? Tim bekerja dengan jumlah tipe manifest yang kecil, tapi berpotensi bertambah di masa depan. Meski aturan umum menyarankan collection terpisah bila sering memfilter berdasarkan tipe, tim menyadari mereka adalah pengecualian: mereka tidak tahu seluruh tipe yang mungkin muncul ke depannya, jumlah tipe bisa bertambah cukup besar, dan mengelola banyak collection dinilai lebih merepotkan dibanding mengelola tipe-tipe tersebut dalam satu collection yang sama.

Types of Partitioning

Dua tipe partisi: vertical partitioning dan horizontal partitioning.

Vertical Partitioning

Vertical partitioning adalah teknik meningkatkan performa basis data dengan memisahkan kolom dari suatu tabel relasional menjadi beberapa tabel terpisah — khususnya berguna saat sebagian kolom sering diakses dan sebagian lagi jarang. Contoh: tabel Images (ImageID, Name, Location, DateCreated, Size, ImageObject) dipecah vertikal menjadi ImageAttributes (metadata yang sering diakses) dan ImageObjects (blob besar yang jarang diakses). Teknik ini lebih umum dipakai pada relational DBMS dibanding document database.

Horizontal Partitioning (Sharding)

Horizontal partitioning adalah proses membagi basis data berdasarkan dokumen (pada document database) atau baris (pada relational database). Bagian-bagian basis data ini disebut shard, disimpan di server terpisah. Sharding adalah proses fundamental yang memungkinkan banyak document database berskala untuk memenuhi kebutuhan aplikasi dengan jumlah user besar atau beban berat lainnya. Saat cluster menerapkan replikasi, satu shard tetap tersedia di banyak server.

Shard key: satu atau lebih key/field yang ada di seluruh dokumen suatu collection, dipakai untuk memisahkan dokumen ke shard berbeda — contoh kandidat shard key: unique document ID, nama, tanggal (mis. tanggal pembuatan), kategori/tipe, region geografis. Shard key menjadi input bagi partitioning algorithm yang menghasilkan penempatan ke shard tertentu.

Algoritma partitioning:

  • Range partitioning: berguna saat shard key punya himpunan nilai terurut (mis. tanggal, angka). Contoh: dokumen dengan field creation date dipartisi per bulan — Shard 1 untuk dokumen dibuat 1–31 Januari 2015, Shard 2 untuk Februari 2015, dst.
  • Hash partitioning: memakai hash function untuk menentukan penempatan dokumen — hash function didesain menghasilkan nilai yang tersebar merata di seluruh rentang nilai fungsinya. Contoh: cluster 8-server dengan hash function menghasilkan nilai 1–8 akan menghasilkan jumlah dokumen yang relatif merata di kedelapan server.
  • List partitioning: memakai himpunan nilai diskret untuk menentukan penempatan data. Contoh: basis data produk dengan beberapa tipe (electronics, appliances, household goods, books, clothes) — tipe produk dipakai sebagai shard key untuk mengalokasikan dokumen ke lima server berbeda.

Sumber

  • D. Sullivan: NoSQL for Mere Mortals, Addison-Wesley, 2015, Chapter 6–7 (Document Databases).
  • Rossel & Manna, “A Big Data Modeling Methodology for NoSQL Document Databases”, Database Systems Journal, vol. XI, 2020.

Flashcard

flashcards Apa keunggulan document database dibanding key-value database murni? :: Atribut-atribut terkait dikelola dalam satu objek (dokumen), sehingga lebih mudah mengembalikan seluruh atribut suatu entitas berdasarkan filter pada satu atribut — tanpa perlu query terpisah ke tiap key individual seperti pada key-value database. Apa perbedaan “schemaless” dan “polymorphic schema” pada document database? :: Schemaless berarti tidak ada definisi struktur formal yang wajib dipatuhi; polymorphic schema berarti tetap ada banyak struktur dokumen implisit (berbeda-beda) yang muncul dalam set dokumen suatu collection. Kenapa sebagian tanggung jawab validasi data berpindah ke kode aplikasi pada document database? :: Karena document database management tidak bisa menegakkan aturan berbasis struktur (field wajib, rentang nilai valid, dsb.) tanpa schema formal — validasi ini harus diimplementasikan lewat kode aplikasi, kecuali untuk unique identifier yang tetap ditegakkan sistem. Apa perbedaan embedding dan referencing pada pemodelan relasi document database, dan kapan masing-masing dipilih? :: Embedding menyimpan dokumen terkait di dalam dokumen lain (cocok untuk one-to-one dan one-to-many dengan child kecil); referencing menyimpan relasi lewat ID ke collection terpisah (cocok untuk many-to-many dan subdokumen besar yang diakses independen). Sebutkan empat faktor yang perlu dipertimbangkan saat memilih embedding vs referencing :: Access pattern (sering diakses bersama vs independen), ukuran & pertumbuhan data, frekuensi update (atomik vs independen), dan kompleksitas skema (sederhana/hierarkis vs kompleks/berevolusi). Kenapa denormalisasi berlebihan pada document database bisa merugikan performa? :: Dokumen yang terlalu besar menyebabkan lebih sedikit dokumen yang terambil per pembacaan blok data dari persistent storage, sehingga meningkatkan total jumlah pembacaan blok yang diperlukan. Apa risiko fisik dari mengizinkan dokumen bertambah besar secara organik (mutable document), dan bagaimana solusinya? :: Dokumen yang tumbuh melampaui ruang yang dialokasikan bisa dipindahkan (moved) ke lokasi storage baru, membebani sistem; solusinya adalah mengalokasikan ruang cukup sejak dokumen dibuat (mis. array dengan slot default sejumlah maksimum yang diperkirakan). Kenapa aplikasi read-heavy dan write-heavy butuh strategi index yang berbeda, dan apa solusi saat keduanya harus didukung sekaligus? :: Read-heavy diuntungkan index pada hampir semua field (query bersifat iteratif); write-heavy dirugikan index (menambah beban CPU/storage/waktu tulis) — solusinya memisahkan menjadi dua basis data (satu dituning untuk write, satu untuk read) dihubungkan lewat proses ETL. Sebutkan dua pola utama memodelkan hierarki pada document database beserta trade-off-nya :: (1) Parent/child references — ringan tapi perlu traversal berulang untuk jalur penuh; (2) Listing all ancestors — satu dokumen menyimpan seluruh rantai leluhur, memberi kelebihan satu-kali-baca untuk jalur penuh ke root, tapi kekurangan berupa banyak operasi tulis saat hierarki berubah. Apa indikasi bahwa sebuah collection document database sebenarnya mencampur beberapa tipe entitas yang seharusnya dipisah? :: Sering memakai field doc_type untuk memfilter collection, dan/atau kode level tertinggi berisi banyak percabangan if berdasarkan doc_type yang mengarah ke fungsi manipulasi terpisah per tipe. Apa perbedaan vertical partitioning dan horizontal partitioning (sharding)? :: Vertical partitioning memisahkan kolom suatu tabel menjadi beberapa tabel terpisah (lebih umum di relational DBMS); horizontal partitioning (sharding) membagi basis data berdasarkan dokumen/baris menjadi shard yang disimpan di server-server terpisah. Sebutkan tiga algoritma partitioning untuk menempatkan dokumen ke shard, beserta kapan masing-masing cocok dipakai :: Range partitioning (untuk shard key dengan nilai terurut seperti tanggal/angka), hash partitioning (untuk distribusi merata lewat fungsi hash), dan list partitioning (untuk shard key dengan himpunan nilai diskret seperti kategori produk).