Di MongoDB, saat Anda membuat indeks pada bidang yang menampung larik, indeks tersebut secara otomatis dibuat sebagai indeks multikunci.
Indeks multikey mendukung kueri yang efisien terhadap bidang array.
Indeks multikey dapat dibuat untuk array yang menyimpan data skalar (misalnya string, angka, dll) dan dokumen bersarang.
Contoh
Misalkan kita memiliki koleksi yang disebut products
yang berisi dokumen-dokumen berikut:
{ "_id" : 1, "product" : "Bat", "sizes" : [ "S", "M", "L" ] }
{ "_id" : 2, "product" : "Hat", "sizes" : [ "S", "L", "XL" ] }
{ "_id" : 3, "product" : "Cap", "sizes" : [ "M", "L" ] }
Kita dapat membuat indeks multikey pada koleksi itu seperti ini:
db.products.createIndex(
{
"sizes": 1
}
)
Ini seperti membuat indeks biasa. Anda tidak perlu secara eksplisit menentukan bahwa itu adalah indeks multikey. MongoDB dapat menentukan bahwa bidang tersebut menampung array, dan karenanya membuatnya sebagai indeks multikey.
Dengan indeks multikey, MongoDB membuat kunci indeks untuk setiap elemen dalam array.
Indeks Multikey Gabungan pada Dokumen Tersemat
Seperti yang disebutkan, Anda dapat membuat indeks multikunci untuk larik yang menyimpan dokumen yang disematkan.
Anda dapat membuat indeks gabungan pada ini, sehingga indeks Anda dibuat terhadap beberapa bidang dalam larik.
Misalkan kita memiliki koleksi yang disebut restaurants
dengan dokumen seperti ini:
db.restaurants.insertMany([ { _id: 1, name: "The Rat", reviews: [{ name: "Stanley", date: "04 December, 2020", ordered: "Dinner", rating: 1 }, { name: "Tom", date: "04 October, 2020", ordered: "Lunch", rating: 2 }] }, { _id: 2, name: "Yum Palace", reviews: [{ name: "Stacey", date: "08 December, 2020", ordered: "Lunch", rating: 3 }, { name: "Tom", date: "08 October, 2020", ordered: "Breakfast", rating: 4 }] }, { _id: 3, name: "Boardwalk Cafe", reviews: [{ name: "Steve", date: "20 December, 2020", ordered: "Breakfast", rating: 5 }, { name: "Lisa", date: "25 October, 2020", ordered: "Dinner", rating: 5 }, { name: "Kim", date: "21 October, 2020", ordered: "Dinner", rating: 5 }] } ])
Kita bisa membuat indeks multikey majemuk seperti ini:
db.restaurants.createIndex(
{
"reviews.ordered": 1,
"reviews.rating": -1
}
)
Sekarang, indeks multikey akan digunakan setiap kali kita menjalankan kueri yang melibatkan bidang tersebut.
Berikut tampilan rencana kueri saat kami menelusuri salah satu bidang tersebut:
db.restaurants.find( { "reviews.ordered": "Dinner" } ).explain()
Hasil:
{ "queryPlanner" : { "plannerVersion" : 1, "namespace" : "krankykranes.restaurants", "indexFilterSet" : false, "parsedQuery" : { "reviews.ordered" : { "$eq" : "Dinner" } }, "queryHash" : "A01226B4", "planCacheKey" : "0E761583", "winningPlan" : { "stage" : "FETCH", "inputStage" : { "stage" : "IXSCAN", "keyPattern" : { "reviews.ordered" : 1, "reviews.rating" : -1 }, "indexName" : "reviews.ordered_1_reviews.rating_-1", "isMultiKey" : true, "multiKeyPaths" : { "reviews.ordered" : [ "reviews" ], "reviews.rating" : [ "reviews" ] }, "isUnique" : false, "isSparse" : false, "isPartial" : false, "indexVersion" : 2, "direction" : "forward", "indexBounds" : { "reviews.ordered" : [ "[\"Dinner\", \"Dinner\"]" ], "reviews.rating" : [ "[MaxKey, MinKey]" ] } } }, "rejectedPlans" : [ ] }, "ok" : 1 }
Bagian yang bertuliskan IXSCAN
berarti telah melakukan pemindaian indeks. Jika tidak menggunakan indeks, itu akan melakukan pemindaian koleksi (COLLSCAN
).
Sama halnya ketika kita melakukan query yang melibatkan kedua field dalam indeks:
db.restaurants.find( { "reviews.ordered": "Dinner", "reviews.rating": { $gt: 3 } } ).explain()
Hasil:
{ "queryPlanner" : { "plannerVersion" : 1, "namespace" : "krankykranes.restaurants", "indexFilterSet" : false, "parsedQuery" : { "$and" : [ { "reviews.ordered" : { "$eq" : "Dinner" } }, { "reviews.rating" : { "$gt" : 3 } } ] }, "queryHash" : "C770E210", "planCacheKey" : "447B5666", "winningPlan" : { "stage" : "FETCH", "filter" : { "reviews.rating" : { "$gt" : 3 } }, "inputStage" : { "stage" : "IXSCAN", "keyPattern" : { "reviews.ordered" : 1, "reviews.rating" : -1 }, "indexName" : "reviews.ordered_1_reviews.rating_-1", "isMultiKey" : true, "multiKeyPaths" : { "reviews.ordered" : [ "reviews" ], "reviews.rating" : [ "reviews" ] }, "isUnique" : false, "isSparse" : false, "isPartial" : false, "indexVersion" : 2, "direction" : "forward", "indexBounds" : { "reviews.ordered" : [ "[\"Dinner\", \"Dinner\"]" ], "reviews.rating" : [ "[MaxKey, MinKey]" ] } } }, "rejectedPlans" : [ ] }, "ok" : 1 }
Namun, jika salah satu bidang dalam kueri tidak disertakan dalam indeks, maka hasil pemindaian koleksi:
db.restaurants.find( { "reviews.name": "Lisa", "reviews.rating": { $gt: 3 } } ).explain()
Hasil:
{ "queryPlanner" : { "plannerVersion" : 1, "namespace" : "krankykranes.restaurants", "indexFilterSet" : false, "parsedQuery" : { "$and" : [ { "reviews.name" : { "$eq" : "Lisa" } }, { "reviews.rating" : { "$gt" : 3 } } ] }, "queryHash" : "49EF83EC", "planCacheKey" : "3C60321C", "winningPlan" : { "stage" : "COLLSCAN", "filter" : { "$and" : [ { "reviews.name" : { "$eq" : "Lisa" } }, { "reviews.rating" : { "$gt" : 3 } } ] }, "direction" : "forward" }, "rejectedPlans" : [ ] }, "ok" : 1 }