除了MongoDB自己创建的_id索引,它还支持创建针对文档的单键索引,用户可以根据自身需求来定义是升序索引还是降序索引。
对于一个单键索引来说,不必关心索引的排序方向,因为MongoDB可以从任意一个方向进行遍历。
创建升序单键索引
这里有一个achievement库,里面包含一些以下数据结构的数据:
{
"_id" : ObjectId("5837080221f5ea1660d59910"),
"student_name" : "student_4396",
"score" : 85
}
接下来我们对score键创建一个单键索引,代码如下:
> db.achievement.createIndex({"score": 1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
索引键指定的值描述了索引键的种类,在单键索引中,索引键指定为1代表按照升序排列,索引键指定为-1代表按照降序排列。
以下的这些操作都会使用索引进行查询。
db.achievement.find({"score" : "85"}).explain()
{
...
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.achievement",
"indexFilterSet" : false,
"parsedQuery" : {
"score" : {
"$eq" : "85"
}
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
...
对内嵌字段创建索引
你可以像对文档中第一层的字段加索引那样,对文档中的内嵌文档加索引,内嵌子段索引和内嵌文档索引是两个不同的概念,你可以使用”.”来索引到内嵌文档中。
现在achievement中又加入了一列address字段,address字段的值是一个内嵌文档,其中包含了国家、省、市等信息,具体的数据结构如下所示:
下面我们创建一个内嵌字段索引:
db.achievement.createIndex({“address.province” : 1})
接下来,我们进行一些根据指定内嵌字段索引的查询,看看MongoDB的解释:
> db.achievement.find({"address.province" : "Beijing"}).explain()
{
...
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"address.province" : 1
},
"indexName" : "address.province_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"address.province" : [
"[\"Beijing\", \"Beijing\"]"
]
}
}
},
...
}
对内嵌文档创建索引
内嵌文档的键其实属于每个文档的第一层数据信息,如果把对应的值看成一个黑盒,其实,内嵌文档和基本类型的值几乎无差别,按照此种理论,对内嵌文档创建索引也是可行的。
比如,我们对address创建一个索引:
db.achievement.createIndex({"address" : 1})
这个内嵌文档索引包含了country、province以及city三个内嵌字段,接下来我们对做一些查询测试:
db.achievement.find({"address" : {"country" : "China", "province" : "Beijing", "city" : "Beijing"}})
db.achievement.find({"address" : {"province" : "Heilongjiang", "city" : "Haerbin"}})
db.achievement.find({"address" : {"city" : "Beijing"}})
测试结果:
> db.achievement.find({"address" : {"country" : "China", "province" : "Beijing", "city" : "Beijing"}}).explain()
{
...
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"address" : 1
},
"indexName" : "address_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"address" : [
"[{ country: \"China\", province : \"Beijing\", city: \"Beijing\" }, { country: \"China\", province: \"Beijing\", city: \"Beijing\" }]"
]
}
}
},
...
}
> db.achievement.find({"address" : {"province" : "Heilongjiang", "city" : "Haerbin"}}).explain()
{
...
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"address" : 1
},
"indexName" : "address_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"address" : [
"[{ province: \"Heilongjiang\", city: \"Haerbin\" }, { province: \"Heilongjiang\", city: \"Haerbin\"}]"
]
}
}
},
...
}
> db.achievement.find({"address" : {"city" : "Beijing"}}).explain()
{
...
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"address" : 1
},
"indexName" : "address_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"address" : [
"[{ city: \"Beijing\" }, { city: \"Beijing\" }]"
]
}
}
},
...
}
小贴士
虽然有些查询可以使用索引,但是貌似结果集中没有包含示例中的文档,这是因为在使用内嵌文档索引做等值匹配时,进行的是精确匹配,也就是查询条件中内嵌文档字段的顺序完全匹配创建内嵌文档索引中字段的顺序。
注意事项
如果你的单集合数据集比较大,在创建索引的过程中需要继续获取数据,这个时候可以考虑在后台建立索引。