Query harga di Chapter sebelumnya berubah drastis setelah satu baris createIndex(). Bentuk index paling sederhana — dan yang akan kita pakai paling sering — adalah single field index: index pada tepat satu field. Chapter ini membedah cara membuatnya, struktur B-tree yang menyimpan nilainya, arti arah 1 dan -1, cara memeriksa dan menghapus index, serta index _id yang selalu hadir otomatis di setiap collection.
Peta materi Chapter ini:
createIndex()satu field beserta pemeriksaan lewatgetIndexes().- Struktur B-tree: kenapa nilai terurut membuat pencarian cepat.
- Arah
1dan-1pada single field index. dropIndex()dan index_idyang tidak bisa dihapus.
Membuat dan Memeriksa Index #
Gunakan kembali katalog delapan buku kita:
use latihan_index
db.buku.drop()
db.buku.insertMany([
{ judul: "Laut Bercerita", penulis: "Leila S. Chudori", harga: 98000, kategori: "fiksi", tag: ["fiksi", "sastra", "penghargaan"], stok: 12 },
{ judul: "Bumi", penulis: "Tere Liye", harga: 89000, kategori: "fiksi", tag: ["fiksi", "remaja", "fantasi"], stok: 25 },
{ judul: "Filosofi Teras", penulis: "Henry Manampiring", harga: 89000, kategori: "nonfiksi", tag: ["filsafat", "pengembangan diri"], stok: 18 },
{ judul: "Atomic Habits", penulis: "James Clear", harga: 115000, kategori: "nonfiksi", tag: ["pengembangan diri", "terjemahan"], stok: 30 },
{ judul: "Rumah Kaca", penulis: "Tere Liye", harga: 72000, kategori: "fiksi", tag: ["fiksi", "remaja"], stok: 9 },
{ judul: "Bumi Manusia", penulis: "Pramoedya A. Toer", harga: 105000, kategori: "sastra", tag: ["sastra", "sejarah"], stok: 15 },
{ judul: "Hujan Bulan Juni", penulis: "Sapardi Djoko Damono", harga: 65000, kategori: "puisi", tag: ["puisi", "sastra"], stok: 8 },
{ judul: "Ensiklopedia Sains Populer", penulis: "Tim Sains", harga: 250000, kategori: "referensi", tag: ["referensi", "sains"], stok: 4 }
])Output yang Dihasilkan:
switched to db latihan_index
true
{
acknowledged: true,
insertedIds: {
'0': ObjectId('6ad3b359fa2dc9c2fb4c00e9'),
'1': ObjectId('6ad3b359fa2dc9c2fb4c00ea'),
'2': ObjectId('6ad3b359fa2dc9c2fb4c00eb'),
'3': ObjectId('6ad3b359fa2dc9c2fb4c00ec'),
'4': ObjectId('6ad3b359fa2dc9c2fb4c00ed'),
'5': ObjectId('6ad3b359fa2dc9c2fb4c00ee'),
'6': ObjectId('6ad3b359fa2dc9c2fb4c00ef'),
'7': ObjectId('6ad3b359fa2dc9c2fb4c00f0')
}
}createIndex() menerima object yang memetakan field ke arah urutan: 1 menaik, -1 menurun. Method ini mengembalikan nama index yang terbentuk, lalu getIndexes() memperlihatkan seluruh index pada collection:
db.buku.createIndex({ harga: 1 })
db.buku.getIndexes()Output yang Dihasilkan:
harga_1
[
{
v: 2,
key: { _id: 1 },
name: '_id_',
collation: { locale: 'simple' }
},
{
v: 2,
key: { harga: 1 },
name: 'harga_1',
collation: { locale: 'simple' }
}
]Dua entry tersebut perlu dibedah:
_id_: index bawaan yang dibuat MongoDB secara otomatis untuk setiap collection, atas field_id. Kita tidak pernah membuatnya secara manual.harga_1: index baru kita. Penamaan defaultnya adalah nama field diikuti arah —harga+_1. Opsinameuntuk memberi nama sendiri dibahas di Chapter Index Properties.key: { harga: 1 }: pola (key pattern) index — field apa yang di-index dan dengan arah apa.
Query pada field harga kini memakai index. Rencana eksekusinya menunjukkan tahap IXSCAN dengan batas pencarian yang sempit:
db.buku.find({ harga: 89000 }, { _id: 0, judul: 1, harga: 1 })
const rencana = db.buku.find({ harga: 89000 }).explain()
printjson(rencana.queryPlanner.winningPlan.inputStage)Output yang Dihasilkan:
[
{ judul: 'Bumi', harga: 89000 },
{ judul: 'Filosofi Teras', harga: 89000 }
]
{
stage: 'IXSCAN',
nss: 'latihan_index.buku',
keyPattern: {
harga: 1
},
indexName: 'harga_1',
isMultiKey: false,
multiKeyPaths: {
harga: []
},
isUnique: false,
isSparse: false,
isPartial: false,
indexVersion: 2,
direction: 'forward',
indexBounds: {
harga: [
'[89000, 89000]'
]
}
}Field indexBounds adalah bukti langsung manfaat B-tree: pencarian terkunci pada rentang [89000, 89000], bukan seluruh collection. Document lain tidak pernah disentuh.
Struktur B-tree di Balik Layar #
Semua index reguler MongoDB disimpan sebagai B-tree — pohon yang selalu seimbang dengan banyak cabang pada tiap simpulnya. Nilai field terurut dari kiri ke kanan, dan setiap entri menyimpan pasangan kunci → penunjuk document.
Diagram di atas memperlihatkan isi konseptual index harga_1 (nilai lain berada di simpul yang tidak digambar). Mencari 89000 berarti: bandingkan dengan akar (85000), ambil cabang kanan, temukan 89000 — dua langkah, berapa pun jumlah document di bawahnya. Itulah pertumbuhan logaritmik yang kita hitung di Chapter sebelumnya: menambah ribuan judul baru hanya menambah satu atau dua tingkat pohon.
Dua konsekuensi struktur ini layak diingat. Pertama, index menyimpan nilai field — bukan document — sehingga ukurannya ditentukan ukuran nilai, bukan ukuran document penuh. Kedua, karena nilai terurut, index juga siap melayani pengurutan dan rentang ($gt, $lt, $gte, $lte) tanpa kerja tambahan.
Arah 1 dan -1 pada Single Field #
Untuk index satu field, arah 1 atau -1 tidak memengaruhi query filter — pencarian nilai tepat sama cepat di kedua arah. Arah baru terasa saat melayani sort(). Index { harga: 1 } menyimpan nilai menaik, tetapi MongoDB dapat memindainya mundur untuk menghasilkan urutan menurun:
const rencana = db.buku.find({}, { _id: 0, judul: 1, harga: 1 }).sort({ harga: -1 }).explain()
printjson(rencana.queryPlanner.winningPlan.inputStage.inputStage)Output yang Dihasilkan:
{
stage: 'IXSCAN',
nss: 'latihan_index.buku',
keyPattern: {
harga: 1
},
indexName: 'harga_1',
isMultiKey: false,
multiKeyPaths: {
harga: []
},
isUnique: false,
isSparse: false,
isPartial: false,
indexVersion: 2,
direction: 'backward',
indexBounds: {
harga: [
'[MaxKey, MinKey]'
]
}
}Perhatikan direction: 'backward' — index dipindai dari ujung besar ke ujung kecil, sehingga hasil sudah terurut menurun tanpa tahap SORT di memori. Kesimpulan praktisnya sederhana namun penting:
| Kebutuhan | Index yang perlu dibuat |
|---|---|
Filter harga (nilai tepat atau rentang) | { harga: 1 } atau { harga: -1 } — sama saja |
sort({ harga: 1 }) | { harga: 1 } (atau { harga: -1 } dipindai mundur) |
sort({ harga: -1 }) | { harga: 1 } (dipindai mundur) — cukup satu index |
Satu index { harga: 1 } melayani kedua arah sort. Arah baru menjadi krusial pada index multi-field — dibahas khusus di Chapter Compound Index dan Index Ordering.
Menghapus Index dan Index _id #
Index yang tidak terpakai sebaiknya dihapus agar tidak menambah biaya tulis. dropIndex() menerima nama index — ambil dari getIndexes():
const hasil = db.buku.dropIndex("harga_1")
printjson({ jumlahIndexSebelumnya: hasil.nIndexesWas, status: hasil.ok })
db.buku.getIndexes()Output yang Dihasilkan:
{ jumlahIndexSebelumnya: 2, status: 1 }
[
{
v: 2,
key: { _id: 1 },
name: '_id_',
collation: { locale: 'simple' }
}
]Nilai jumlahIndexSebelumnya: 2 mencatat jumlah index sebelum penghapusan — setelahnya tersisa satu. Yang tersisa itu, _id_, tidak bisa dihapus:
try {
db.buku.dropIndex("_id_")
} catch (e) {
print("Galat: " + e.message)
}Output yang Dihasilkan:
Galat: cannot drop _id indexRangkuman #
db.collection.createIndex({ field: 1 })membuat single field index;getIndexes()mendaftarkan semua index beserta key pattern dan namanya.- Nama default index adalah
<field>_<arah>, misalnyaharga_1; index_id_selalu ada otomatis dan tidak dapat dihapus. - Index disimpan sebagai B-tree terurut: pencarian nilai, rentang, dan sort sama-sama diuntungkan.
- Pada single field index, arah
1/-1tidak memengaruhi filter; satu index melayani sort dua arah lewat pemindaian maju dan mundur (direction: 'forward'/'backward'). dropIndex("nama")menghapus index berdasarkan nama, bukan key pattern.