Memahami mengapa index mengubah pencarian dari collection scan O(N) menjadi index scan O(log N), mengenal tujuh tipe index MongoDB dari single field, compound dengan aturan ESR, multikey, hingga wildcard, TTL, unique, dan partial, serta kapan memakai masing-masing.

Semua query yang kalian tulis sejauh ini bisa berjalan tanpa index — MongoDB cukup memindai seluruh dokumen. Masalahnya, "bisa berjalan" adalah standar yang sangat rendah. Saat collection tumbuh ke jutaan dokumen, query tanpa index menjadi lambat hingga tidak layak dipakai produksi. Inilah pekerjaan index: membuat MongoDB menemukan data tanpa harus melihat setiap dokumen.
Episode 12 adalah gerbang menuju MongoDB yang benar-benar performan. Roadmap-nya: pertama kita pahami mengapa index krusial, kedua single field index, ketiga compound index dengan aturan ESR, keempat multikey dan wildcard index, dan kelima index fungsional — TTL, unique, dan partial. Mari mulai.
Tanpa index, MongoDB melakukan COLLSCAN (collection scan): membaca setiap dokumen satu per satu untuk mengecek kecocokan. Kompleksitasnya linear, O(N) — kalikan dua juta dokumen dengan waktu baca per dokumen, dan query menjadi sangat lambat.
Dengan index, MongoDB melakukan IXSCAN (index scan): mencari di struktur B-Tree yang terurut — seperti mencari kata di kamus, bukan membaca seluruh buku. Kompleksitasnya logaritmik, O(log N). Untuk 2 juta dokumen, perbedaannya bisa ratusan kali lipat:
Collection scan : O(N) -> baca 2.000.000 dokumen
Index scan : O(log N) -> baca sekitar 21 langkahPrinsipnya mirip daftar isi di buku besar: index menyimpan salinan field tertentu dalam urutan terurut, beserta penunjuk ke lokasi dokumen aslinya. Query yang memakai field ber-index langsung menuju lokasi yang tepat tanpa membaca semua dokumen.
Index memakai ruang penyimpanan ekstra dan sedikit memperlambat insert/update (karena index harus dirawat), tapi keuntungan membaca yang diberikannya jauh melampaui biaya itu untuk workload baca yang dominan.
Index paling sederhana: satu field, diurutkan ascending (1) atau descending (-1):
db.users.createIndex({ email: 1 })
db.products.createIndex({ price: -1 })Untuk query yang menyaring atau mengurutkan berdasarkan satu field — pencarian email, sorting harga — index ini langsung bekerja. Arah sorting (1/-1) hampir tidak berpengaruh untuk pencarian kesetaraan, tapi penting untuk sort: index { price: -1 } bisa melayani sort({ price: -1 }) tanpa pengurutan tambahan di memory.
Compound index menggabungkan beberapa field dalam satu index. Query yang menyaring atau mengurutkan kombinasi field — misal { category: "elektronik", price: { $lt: 500000 } } — bisa diselesaikan seluruhnya dengan satu index, jauh lebih cepat daripada dua index terpisah:
db.products.createIndex({ category: 1, price: -1 })Urutan field dalam compound index sangat penting. Index { category: 1, price: -1 } melayani query yang menyaring category saja, category + price, atau mengurutkan kombinasi keduanya — tapi tidak efisien untuk query yang hanya menyaring price saja.
Untuk merancang compound index yang optimal, ikuti aturan ESR:
$lt, $gt), di urutan terakhir.db.orders.createIndex({ userId: 1, createdAt: -1, total: 1 })Index di atas dirancang untuk query { userId: "x", createdAt: { $gte: date }, total: { $gt: 100 } } dengan sort createdAt — field kesetaraan userId lebih dulu, lalu sort createdAt, dan rentang total di akhir. Ini memungkinkan MongoDB menggunakan satu index untuk filter sekaligus sort tanpa operasi tambahan.
Saat field yang di-index berupa array, MongoDB otomatis membuat multikey index — index yang menyimpan setiap elemen array sebagai entri. Kalian tidak perlu melakukan apa pun khusus; cukup buat index biasa pada field array:
db.products.createIndex({ tags: 1 })Index ini membuat query find({ tags: "best-seller" }) menjadi index scan, bukan collection scan. Multikey index terjadi otomatis saat MongoDB mendeteksi array pada field yang di-index. Catatan penting: multikey index tidak bisa menjadi komponen geospatial atau melakukan komposisi index pada beberapa field array sekaligus.
Wildcard index meng-index semua field dari sebuah dokumen tanpa harus mendaftar namanya satu per satu. Ini penyelamat untuk schema dinamis — misal produk dengan atribut yang tidak terprediksi:
db.products.createIndex({ "$**": 1 })Wildcard index menjamin field apa pun yang kalian tambahkan di masa depan otomatis ter-index. Tapi ia memakai lebih banyak ruang daripada index selektif — pakai sebagai jaring pengaman untuk dokumen dengan struktur dinamis, bukan pengganti index terarah pada field yang memang pasti dipakai query utama.
TTL (Time To Live) index secara otomatis menghapus dokumen setelah durasi tertentu sejak nilai field tanggalnya. Sempurna untuk session data, log sementara, atau kode OTP:
db.sessions.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })Setiap jam, thread monitor MongoDB menghapus dokumen yang createdAt-nya sudah lebih dari 3600 detik. Data "kadaluarsa" dibersihkan tanpa cron job manual. Perhatikan: field yang dipakai harus berisi Date, dan TTL tidak berlaku untuk collection capped.
Unique index mencegah nilai duplikat pada field — aturan yang setara dengan PRIMARY KEY atau UNIQUE constraint di RDBMS:
db.users.createIndex({ email: 1 }, { unique: true })Setelah index ini dibuat, dua dokumen dengan email sama akan ditolak — proteksi paling andal terhadap duplikasi data, lebih kuat daripada validasi aplikasi karena ditegakkan langsung oleh database.
Partial index hanya meng-index dokumen yang memenuhi partialFilterExpression. Menghemat ruang dan mempercepat insert karena dokumen di luar kriteria tidak di-index:
db.users.createIndex(
{ email: 1 },
{ unique: true, partialFilterExpression: { status: "active" } }
)Contoh di atas menggabungkan unique + partial: email unik hanya dijamin di antara user berstatus active. User yang dinonaktifkan bisa memiliki email duplikat — perilaku yang kadang diinginkan untuk soft-delete user yang emailnya dipakai ulang.
Info
Aturan praktis jumlah index: untuk workload umum, mulailah dengan 2-5 index per collection yang benar-benar melayani query utama kalian. Setiap index tambahan memperlambat write dan memakan disk. Gunakan compound index ESR untuk melayani beberapa query sekaligus, dan jangan membuat index hanya karena "sepertinya perlu". Kita akan membuktikan nilai sebuah index dengan explain() di episode 13.
Warning
Waspadai indeks yang saling tumpang tindih. Compound index { a: 1, b: 1 } sudah melayani query yang hanya menyaring a — menambahkan index { a: 1 } lagi adalah pemborosan. Prinsip prefix: compound index bisa melayani query apa pun yang memakai prefiks field-nya. Audit index kalian secara berkala dan buang yang redundan.
Pada episode 12 ini kalian telah memahami mengapa indexing mengubah performa dari collection scan O(N) menjadi index scan O(log N), serta mengenal tujuh tipe index: single field, compound dengan aturan ESR (Equality, Sort, Range), multikey yang otomatis untuk array, wildcard untuk schema dinamis, TTL untuk penghapusan otomatis berbasis waktu, unique untuk menjamin keunikan, dan partial untuk meng-index subset dokumen saja.
Inti yang harus dibawa pulang:
O(N) menjadi O(log N) — investasi paling berdampak di MongoDB.Di episode 13 berikutnya kita membuktikan semua teori index dengan bukti nyata: Query Optimization & explain() Analysis. Kalian akan membaca execution plan, membedakan COLLSCAN dari IXSCAN, memahami winning plan versus rejected plans, serta mengaktifkan database profiler untuk menemukan slow queries di produksi. Sampai jumpa di episode 13!