MongoDB允许深入文档内部,对嵌套字段和数组建立索引;嵌套对象和数组字段可以和复合索引中的顶级字段一起使用,多数情况下与“正常”索引字段的行为也是一致的。考虑以下文档集合(user ):
db.user.insertMany([{"address": {"province": "HeNan","city": "ZhengZhou","pincode": "123"},"tags": ["music","cricket","blogs"],"name": "fly"},{"address": {"province": "HeBei","city": "HanDan","pincode": "234"},"tags": ["music","basket","blogs"],"name": "chen"},{"address": {"province": "ChongQing","city": "ChongQing","pincode": "456"},"tags": ["music","writing","running"],"name": "wang"}])
以上文档包含了 address 子文档和 tags 数组。
索引数组字段
- 假设我们基于标签来检索用户,为此我们需要对集合中的数组 tags 建立索引。
- 在数组中创建索引,需要对数组中的每个字段依次建立索引。所以在我们为数组 tags 创建索引时,会为 music、cricket、blogs三个值建立单独的索引。
- 使用以下命令创建数组索引:
db.user.ensureIndex({"tags":1})
- 创建索引后,我们可以这样检索集合的 tags 字段:
db.user.find({tags:"music"})
- 为了验证我们使用使用了索引,可以使用 explain 命令:
db.user.find({tags:"music"}).explain()- 执行结果
/* 1 */{"queryPlanner" : {"plannerVersion" : 1,"namespace" : "mongotest.user","indexFilterSet" : false,"parsedQuery" : {"tags" : {"$eq" : "music"}},"winningPlan" : {"stage" : "FETCH","inputStage" : {"stage" : "IXSCAN","keyPattern" : {"tags" : 1.0},"indexName" : "tags_1","isMultiKey" : true,"multiKeyPaths" : {"tags" : ["tags"]},"isUnique" : false,"isSparse" : false,"isPartial" : false,"indexVersion" : 2,"direction" : "forward","indexBounds" : {"tags" : ["[\"music\", \"music\"]"]}}},"rejectedPlans" : []},"serverInfo" : {"host" : "kf-PC","port" : 27017,"version" : "3.4.9","gitVersion" : "876ebee8c7dd0e2d992f36a848ff4dc50ee6603e"},"ok" : 1.0}
- 以上命令执行结果中会显示 "stage":"FETCH",,则表示已经使用了索引。
stage的类型的意义mongodb的文档中列出了前4种类型,还有一些没有列出来,但是会比较常见,这里一并解释一下。COLLSCAN :全表扫描IXSCAN:索引扫描FETCH::根据索引去检索指定documentSHARD_MERGE:各个分片返回数据进行mergeSORT:表明在内存中进行了排序(与前期版本的scanAndOrder:true一致)SORT_MERGE:表明在内存中进行了排序后再合并LIMIT:使用limit限制返回数SKIP:使用skip进行跳过IDHACK:针对_id进行查询SHARDING_FILTER:通过mongos对分片数据进行查询COUNT:利用db.coll.count()之类进行count运算COUNTSCAN:count不使用用Index进行count时的stage返回COUNT_SCAN:count使用了Index进行count时的stage返回SUBPLA:未使用到索引的$or查询的stage返回TEXT:使用全文索引进行查询时候的stage返回附:explain查询结果解析官方文档:https://docs.mongodb.org/v3.0/reference/explain-results/
数组上的索引(1)可以看得出在数组字段上建立索引的代价比较大,因为每次的删除,更新都会对每一个索引进行刷新,太消耗服务器的资源;(2)可以针对数组字段中的某一个元素做具体的单独索引,减少索引的数量;
- 例如,在数组字段tags中的第1个元素中的music上建立索引:
db.user.ensureIndex({"tags.0.music":1})
- 同样,只有精确匹配tags.0.music查询,上述索引才会起到索引的作用。
多键索引如果在数组字段上创建索引,那么这个索引称为多键索引( multikey)。多键索引用explain函数中可以看到“isMultikey”字段的值为true,多键索引比非多键索引要慢一些;
索引子文档字段
- 假设我们需要通过city、state、pincode字段来检索文档,由于这些字段是子文档的字段,所以我们需要对子文档建立索引。
- 为子文档的三个字段创建索引,命令如下:
db.user.ensureIndex({"address.province":1,"address.city":1,"address.pincode":1})利用这种方式可以建立任意深度的索引,例如可以在X.Y.Z.A.B.C上建立索引。但是,针对子文档“address”上建立的索引,和建立在子文档的某个字段“address.provincey”上的索引是不同的:(1)对整个子文档上建立的索引,只会提高整个子文档的的查询速度;- 也就是说只有在完全匹配子文档的查询(包括字段顺序),子文档索引才会起作用;
(2)只有查询address.province字段,索引address.province才会起作用,其他情况索引address.province不起作用;
- 一旦创建索引,我们可以使用子文档的字段来检索数据:
db.user.find({"address.province":"HeNan"})
- 记住查询表达式必须遵循指定的索引的顺序。所以上面创建的索引将支持以下查询:
db.user.find({"address.province":"HeNan","address.city":"ZhengZhou"})
- 同样支持以下查询:
db.user.find({"address.province":"HeNan","address.city":"ZhengZhou","address.pincode":"123"})查询分析/* 1 */{"queryPlanner" : {"plannerVersion" : 1,"namespace" : "mongotest.user","indexFilterSet" : false,"parsedQuery" : {"$and" : [{"address.city" : {"$eq" : "ZhengZhou"}},{"address.pincode" : {"$eq" : "123"}},{"address.province" : {"$eq" : "HeNan"}}]},"winningPlan" : {"stage" : "FETCH","inputStage" : {"stage" : "IXSCAN","keyPattern" : {"address.province" : 1.0,"address.city" : 1.0,"address.pincode" : 1.0},"indexName" : "address.province_1_address.city_1_address.pincode_1","isMultiKey" : false,"multiKeyPaths" : {"address.province" : [],"address.city" : [],"address.pincode" : []},"isUnique" : false,"isSparse" : false,"isPartial" : false,"indexVersion" : 2,"direction" : "forward","indexBounds" : {"address.province" : ["[\"HeNan\", \"HeNan\"]"],"address.city" : ["[\"ZhengZhou\", \"ZhengZhou\"]"],"address.pincode" : ["[\"123\", \"123\"]"]}}},"rejectedPlans" : []},"serverInfo" : {"host" : "kf-PC","port" : 27017,"version" : "3.4.9","gitVersion" : "876ebee8c7dd0e2d992f36a848ff4dc50ee6603e"},"ok" : 1.0}
参考来源: http://www.runoob.com/mongodb/mongodb-advanced-indexing.html
参考来源:http://281816327.blog.51cto.com/907015/1601473