Lets learn about multikey indexes and how they are efficient in MongoDB.
database name: daily
collections: gadgets, users
Insert documents into gadgets collection
> use daily
switched to db daily
> db.gadgets.insert({_id: 1, gadget: "Nexus 5"});
WriteResult({ "nInserted" : 1 })
> db.gadgets.insert({_id: 2, gadget: "iPhone"});
WriteResult({ "nInserted" : 1 })
> db.gadgets.insert({_id: 3, gadget: "iPad"});
WriteResult({ "nInserted" : 1 })
> db.gadgets.insert({_id: 4, gadget: "Nexus 7"});
WriteResult({ "nInserted" : 1 })
> db.gadgets.find()
{ "_id" : 1, "gadget" : "Nexus 5" }
{ "_id" : 2, "gadget" : "iPhone" }
{ "_id" : 3, "gadget" : "iPad" }
{ "_id" : 4, "gadget" : "Nexus 7" }
Here we have 4 documents with “_id” as 1, 2, 3, 4.
Insert documents into users collection
> db.users.insert({name: "Satish",
products: [db.gadgets.find()[0]._id,
db.gadgets.find()[3]._id]});
WriteResult({ "nInserted" : 1 })
> db.users.insert({name: "Kiran",
products: [db.gadgets.find()[0]._id,
db.gadgets.find()[3]._id,
db.gadgets.find()[2]._id]});
WriteResult({ "nInserted" : 1 })
> db.users.insert({name: "Jyothi", products: [1, 2]});
WriteResult({ "nInserted" : 1 })
> db.users.find().pretty()
{
"_id" : ObjectId("53c7a30efd7d3c9597ca2593"),
"name" : "Satish",
"products" : [
1,
4
]
}
{
"_id" : ObjectId("53c7a337fd7d3c9597ca2594"),
"name" : "Kiran",
"products" : [
1,
4,
3
]
}
{
"_id" : ObjectId("53c7a34efd7d3c9597ca2595"),
"name" : "Jyothi",
"products" : [
1,
2
]
}
Here we insert documents into “users” collection and embed the “_id” value of “gadgets” collection as array elements of “products” key.
Multi-key Index: MongoDB
Command to fetch documents with array element 1 and 4
> db.users.find({products: {$all: [1, 4]}}).pretty();
{
"_id" : ObjectId("53c7a30efd7d3c9597ca2593"),
"name" : "Satish",
"products" : [
1,
4
]
}
{
"_id" : ObjectId("53c7a337fd7d3c9597ca2594"),
"name" : "Kiran",
"products" : [
1,
4,
3
]
}
Both these documents have array values 1 and 4 in them.
Related Read: Comparison Operators: MongoDB
system.indexes content
> show collections
gadgets
system.indexes
users
> db.system.indexes.find()
{ "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "daily.gadgets" }
{ "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "daily.users" }
Here we have only 1 key and it’s on “_id”.
Basic Cursor
> db.users.find({products: {$all: [1, 4]}}).explain();
{
"cursor" : "BasicCursor",
"isMultiKey" : false,
"n" : 2,
"nscannedObjects" : 3,
"nscanned" : 3,
"nscannedObjectsAllPlans" : 3,
"nscannedAllPlans" : 3,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"server" : "Satish-PC:27017",
"filterSet" : false
}
If we chain explain() method to our command, we can know some details about the command and also evaluate about its efficiency. The above command doesn’t have multi-key enabled and it’s a Basic Cursor.
Lets create index on products field
> db.users.ensureIndex({"products": 1});
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
This creates index on field “products”.
Now the system.indexes content
> db.system.indexes.find()
{ "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "daily.gadgets" }
{ "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "daily.users" }
{ "v" : 1, "key" : { "products" : 1 },
"name" : "products_1",
"ns" : "daily.users" }
So now we have 2 keys, “_id” and “products”.
BTree Cursor
> db.users.find({products: {$all: [1, 4]}}).explain();
{
"cursor" : "BtreeCursor products_1",
"isMultiKey" : true,
"n" : 2,
"nscannedObjects" : 3,
"nscanned" : 3,
"nscannedObjectsAllPlans" : 3,
"nscannedAllPlans" : 8,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"products" : [
[
1,
1
]
]
},
"server" : "Satish-PC:27017",
"filterSet" : false
}
Now if we run the same command chained with explain() method, we could see that its a Btree Cursor and multi-key index is true.
Note: Btree Cursors are faster and efficient than Basic Cursors.