MongoDB:16-MongoDB-索引数组字段和索引子文档字段

 

 
  1. MongoDB容许深刻文档内部,对嵌套字段和数组创建索引;
  2. 嵌套对象和数组字段能够和复合索引中的顶级字段一块儿使用,多数状况下与“正常”索引字段的行为也是一致的。
    1.  
    2.  
    1. 考虑如下文档集合(user ):html

    2.  
 
  1. db.user.insertMany(
  2. [
  3. {
  4. "address": {
  5. "province": "HeNan",
  6. "city": "ZhengZhou",
  7. "pincode": "123"
  8. },
  9. "tags": [
  10. "music",
  11. "cricket",
  12. "blogs"
  13. ],
  14. "name": "fly"
  15. },
  16. {
  17. "address": {
  18. "province": "HeBei",
  19. "city": "HanDan",
  20. "pincode": "234"
  21. },
  22. "tags": [
  23. "music",
  24. "basket",
  25. "blogs"
  26. ],
  27. "name": "chen"
  28. },
  29. {
  30. "address": {
  31. "province": "ChongQing",
  32. "city": "ChongQing",
  33. "pincode": "456"
  34. },
  35. "tags": [
  36. "music",
  37. "writing",
  38. "running"
  39. ],
  40. "name": "wang"
  41. }
  42. ]
  43. )

 

 

以上文档包含了 address 子文档和 tags 数组。git

索引数组字段

 

  • 假设咱们基于标签来检索用户,为此咱们须要对集合中的数组 tags 创建索引。
  • 在数组中建立索引,须要对数组中的每一个字段依次创建索引。因此在咱们为数组 tags 建立索引时,会为 music、cricket、blogs三个值创建单独的索引。

 

 

 

    • 使用如下命令建立数组索引:
 
  1. db.user.ensureIndex({"tags":1})

 

 

 

    • 建立索引后,咱们能够这样检索集合的 tags 字段:
 
  1. db.user.find({tags:"music"})

 

 

    • 为了验证咱们使用使用了索引,可使用 explain 命令:
 
  1. db.user.find({tags:"music"}).explain()
 
  1. 执行结果
  2. /* 1 */
  3. {
  4. "queryPlanner" : {
  5. "plannerVersion" : 1,
  6. "namespace" : "mongotest.user",
  7. "indexFilterSet" : false,
  8. "parsedQuery" : {
  9. "tags" : {
  10. "$eq" : "music"
  11. }
  12. },
  13. "winningPlan" : {
  14. "stage" : "FETCH",
  15. "inputStage" : {
  16. "stage" : "IXSCAN",
  17. "keyPattern" : {
  18. "tags" : 1.0
  19. },
  20. "indexName" : "tags_1",
  21. "isMultiKey" : true,
  22. "multiKeyPaths" : {
  23. "tags" : [
  24. "tags"
  25. ]
  26. },
  27. "isUnique" : false,
  28. "isSparse" : false,
  29. "isPartial" : false,
  30. "indexVersion" : 2,
  31. "direction" : "forward",
  32. "indexBounds" : {
  33. "tags" : [
  34. "[\"music\", \"music\"]"
  35. ]
  36. }
  37. }
  38. },
  39. "rejectedPlans" : []
  40. },
  41. "serverInfo" : {
  42. "host" : "kf-PC",
  43. "port" : 27017,
  44. "version" : "3.4.9",
  45. "gitVersion" : "876ebee8c7dd0e2d992f36a848ff4dc50ee6603e"
  46. },
  47. "ok" : 1.0
  48. }

 

 

 

  • 以上命令执行结果中会显示  "stage" : "FETCH",,则表示已经使用了索引。
     
    1. stage的类型的意义
    2. mongodb的文档中列出了前4种类型,还有一些没有列出来,可是会比较常见,这里一并解释一下。
    3.  
    4. COLLSCAN :全表扫描
    5. IXSCAN:索引扫描
    6. FETCH::根据索引去检索指定document
    7. SHARD_MERGE:各个分片返回数据进行merge
    8. SORT:代表在内存中进行了排序(与前期版本的scanAndOrder:true一致)
    9. SORT_MERGE:代表在内存中进行了排序后再合并
    10. LIMIT:使用limit限制返回数
    11. SKIP:使用skip进行跳过
    12. IDHACK:针对_id进行查询
    13. SHARDING_FILTER:经过mongos对分片数据进行查询
    14. COUNT:利用db.coll.count()之类进行count运算
    15. COUNTSCANcount不使用用Index进行count时的stage返回
    16. COUNT_SCANcount使用了Index进行count时的stage返回
    17. SUBPLA:未使用到索引的$or查询的stage返回
    18. TEXT:使用全文索引进行查询时候的stage返回
    19.  
    20. 附:explain查询结果解析官方文档:
    21. https://docs.mongodb.org/v3.0/reference/explain-results/
  • 具体参考:http://blog.csdn.net/fly910905/article/details/78184302
 
  1. 数组上的索引
  2. 1)能够看得出在数组字段上创建索引的代价比较大,由于每次的删除,更新都会对每个索引进行刷新,太消耗服务器的资源;
  3. 2能够针对数组字段中的某一个元素作具体的单独索引,减小索引的数量;
  • 例如,在数组字段tags中的第1个元素中的music上创建索引:
 
  1. db.user.ensureIndex({"tags.0.music":1})
  • 一样,只有精确匹配tags.0.music查询,上述索引才会起到索引的做用。
 
  1. 多键索引
  2. 若是在数组字段上建立索引,那么这个索引称为多键索引( multikey)。
  3. 多键索引用explain函数中能够看到“isMultikey”字段的值为true,多键索引比非多键索引要慢一些;

 

索引子文档字段

 

  • 假设咱们须要经过city、state、pincode字段来检索文档,因为这些字段是子文档的字段,因此咱们须要对子文档创建索引。
    • 为子文档的三个字段建立索引,命令以下:

 

 
  1. db.user.ensureIndex({"address.province":1,"address.city":1,"address.pincode":1})

 

 

 
  1. 利用这种方式能够创建任意深度的索引,例如能够在X.Y.Z.A.B.C上创建索引。
  2. 可是,针对子文档“address”上创建的索引,和创建在子文档的某个字段“address.provincey”上的索引是不一样的:
  3. 1)对整个子文档上创建的索引,只会提升整个子文档的的查询速度;
  4. 也就是说只有在彻底匹配子文档的查询(包括字段顺序),子文档索引才会起做用;
  5. 2)只有查询address.province字段,索引address.province才会起做用,
  6. 其余状况索引address.province不起做用;

 

    • 一旦建立索引,咱们可使用子文档的字段来检索数据:
 
  1. db.user.find({"address.province":"HeNan"})

 

 

 

    • 记住查询表达式必须遵循指定的索引的顺序。因此上面建立的索引将支持如下查询:
 
  1. db.user.find({"address.province":"HeNan","address.city":"ZhengZhou"})

 

 

    • 一样支持如下查询:

 

 

 
  1. db.user.find({"address.province":"HeNan","address.city":"ZhengZhou","address.pincode":"123"})
 
  1. 查询分析
  2. /* 1 */
  3. {
  4. "queryPlanner" : {
  5. "plannerVersion" : 1,
  6. "namespace" : "mongotest.user",
  7. "indexFilterSet" : false,
  8. "parsedQuery" : {
  9. "$and" : [
  10. {
  11. "address.city" : {
  12. "$eq" : "ZhengZhou"
  13. }
  14. },
  15. {
  16. "address.pincode" : {
  17. "$eq" : "123"
  18. }
  19. },
  20. {
  21. "address.province" : {
  22. "$eq" : "HeNan"
  23. }
  24. }
  25. ]
  26. },
  27. "winningPlan" : {
  28. "stage" : "FETCH",
  29. "inputStage" : {
  30. "stage" : "IXSCAN",
  31. "keyPattern" : {
  32. "address.province" : 1.0,
  33. "address.city" : 1.0,
  34. "address.pincode" : 1.0
  35. },
  36. "indexName" : "address.province_1_address.city_1_address.pincode_1",
  37. "isMultiKey" : false,
  38. "multiKeyPaths" : {
  39. "address.province" : [],
  40. "address.city" : [],
  41. "address.pincode" : []
  42. },
  43. "isUnique" : false,
  44. "isSparse" : false,
  45. "isPartial" : false,
  46. "indexVersion" : 2,
  47. "direction" : "forward",
  48. "indexBounds" : {
  49. "address.province" : [
  50. "[\"HeNan\", \"HeNan\"]"
  51. ],
  52. "address.city" : [
  53. "[\"ZhengZhou\", \"ZhengZhou\"]"
  54. ],
  55. "address.pincode" : [
  56. "[\"123\", \"123\"]"
  57. ]
  58. }
  59. }
  60. },
  61. "rejectedPlans" : []
  62. },
  63. "serverInfo" : {
  64. "host" : "kf-PC",
  65. "port" : 27017,
  66. "version" : "3.4.9",
  67. "gitVersion" : "876ebee8c7dd0e2d992f36a848ff4dc50ee6603e"
  68. },
  69. "ok" : 1.0
  70. }

 

参考来源: http://www.runoob.com/mongodb/mongodb-advanced-indexing.htmlmongodb

参考来源:http://281816327.blog.51cto.com/907015/1601473数组

相关文章
相关标签/搜索