女主宣言

MongoDB在4.2 版本推出了Wildcard Indexes,究竟什么是Wildcard Indexes以及Wildcard Indexes适合哪些场景本文结合官方文档以及实际测试进行简单概述。

PS:丰富的一线技术、多元化的表现形式,尽在“360云计算”,点关注哦!

1

通配符索引示例

因为MongoDB是dynamic schemas,所以应用是可以查询任何已知字段或者随机字段的。

假设(此假设案例摘自官方文档),集合colA的UserMetadata字段包含如下数据:

{ "userMetadata" : { "likes" : [ "dogs", "cats" ] } }
{ "userMetadata" : { "dislikes" : "pickles" } }
{ "userMetadata" : { "age" : 45 } }
{ "userMetadata" : "inactive" }

但是在查询的时候可能是如下语句:

db.colA.find({ "userMetadata.likes" : "dogs" })
db.colA.find({ "userMetadata.dislikes" : "pickles" })
db.colA.find({ "userMetadata.age" : { $gt : 30 } })
db.colA.find({ "userMetadata" : "inactive" })

是否能通过一个索引来完成上述需求?

答案是肯定的,上述查询可以通过通配符索引来实现既定需求,也就是 db.colA.createIndex( { "userMetadata.$**" : 1 } )。

那么如何创建通配符索引?

注意:首先应该明确的是通配符索引只在版本兼容性4.2的时候才能创建。

如何查询版本兼容性?

db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

如何设置?

db.adminCommand( { setFeatureCompatibilityVersion: "4.2" } )

2

通配符索引的形式

单字段通配符索引

{"_id" : ObjectId("5ee2df16911d8dfaa91520b4"),"product_name" : "Spy Coat","product_attributes" : {"material" : ["Tweed","Wool","Leather"],"size" : {"length" : 72,"units" : "inches"}}
}
{"_id" : ObjectId("5ee2df30911d8dfaa91520b5"),"product_name" : "Spy Pen","product_attributes" : {"colors" : ["Blue","Black"],"secret_feature" : {"name" : "laser","power" : "1000","units" : "watts"}}
}

如果数据结构是上面这样的,其中product_attributes 属性包含任何的结构。

那么如果我们创建一个这个索引,它会进行什么操作?

db.product_catalog.createIndex({"product_attributes.$**":1})。

因为product_attributes 里面包含数组和嵌套文档等对象,实际创建这个索引后,会迭代嵌套文档或者数组把里面的所有的值都取出来放到索引里。支持如下查询:

db.product_catalog.find({"product_attributes.colors":"Blue"})
db.product_catalog.find({"product_attributes.secret_feature.name":"laser"})
db.product_catalog.find({"product_attributes.size.length":{$gt:60}})

全字段的通配符索引

可以通过下面的语句创建一个索引,索引中包含集合中的所有字段,但是不包括_id(如果想包含_id可以通过wildcardProjection 来设置),如果集合中的字段包含数组或者嵌套对象的话,那么会迭代数组或者嵌套对象并把值放到索引中。

Db.product_catalog.createIndex({“$**”:1})
给每个文档添加一个address的字段。
7777:PRIMARY> db.product_catalog.find().pretty()
{"_id" : ObjectId("5ee2df16911d8dfaa91520b4"),"product_name" : "Spy Coat","product_attributes" : {"material" : ["Tweed","Wool","Leather"],"size" : {"length" : 72,"units" : "inches"}},"address" : "Beijing"
}
{"_id" : ObjectId("5ee2df30911d8dfaa91520b5"),"product_name" : "Spy Pen","product_attributes" : {"colors" : ["Blue","Black"],"secret_feature" : {"name" : "laser","power" : "1000","units" : "watts"}},"address" : "Tianjin"
}db.product_catalog.find({"product_name":"Spy Coat","address":"nanji","product_attributes.colors":"Blue"})

在全字段通配符索引的基础上可以明确包含哪些或者不包含哪些字段到通配符索引中,只能是在全字段通配符索引的基础上,单字段的是不可以的:

在全字段的基础上创建一个明确包含哪些字段的索引:

db.collection.createIndex({ "$**" : 1 },{ "wildcardProjection" :{ "fieldA" : 1, "fieldB.fieldC" : 1 }}
)

注意:通配符索引不支持在使用wildcardProjection的时候混合使用包含和排除语句,除了明确指定包含_id字段的时候。

在全字段的基础上创建一个明确不包含哪些字段的索引:

db.collection.createIndex({ "$**" : 1 },{ "wildcardProjection" :{ "fieldA" : 0, "fieldB.fieldC" : 0 }}
)

3

通配符索引的行为

通配符索引的行为根据其字段类型不同而有所不同。

  • 字段为对象

    如果是对象的话,会将对象中的内容存储到索引中,通配符索引会把对象中的所有嵌套对象加载到索引中。

  • 字段为数组

    如果是数组的话,通配符索引遍历数组并且将每个元素都存储到索引中。

    如果数组中的元素是一个对象的话,通配符索引把对象中的内容加载到索引中,像上面的加载对象一样。

    如果数组中的元素是一个数组的话(就是多维数组),通配符索引并不迭代嵌套数组,相反是把整个嵌套数组作为一个值来看。

  • 其他类型

    把值记录到数组中。

    通配符索引会持续迭代任何的嵌套对象或者数组直到最底层(就是不能在迭代为止),然后它会索引全路径。

通配符索引对于显示数组位置的查询

通配符索引虽然不会记录给定数组中的元素下标,但是,MongoDB仍然可以选择通配符索引来满足包含一个或多个显式数组索引的字段路径的查询(for example, parentArray.0.nestedArray.0)

由于为每个连续嵌套数组定义索引边界的复杂性日益增加,如果该路径包含8个以上的显式数组索引,MongoDB不会考虑使用通配符索引来回答查询中的给定字段路径。MongoDB仍然可以考虑使用通配符索引来回答查询中的其他字段路径。

如果超过了8个以上显示数组索引的话MongoDB 会考虑另外的索引或者执行全集合扫描。如下结构:

{"parentObject" : {"nestedArray" : ["elementOne",{"deeplyNestedArray" : [ "elementTwo" ]}]}
}

请注意,通配符索引本身对索引文档时遍历文档的深度没有任何限制;该限制仅适用于显式指定精确数组索引的查询。通过发出没有显式数组索引的相同查询,MongoDB可以选择通配符索引来回答查询。

4

通配符索引的限制

1.首先通配符索引是一个稀疏索引,只存放存在的字段在索引里面,不存在的不存放,也就是说当你使用{$exists:false}的时候,是不会走索引的,是全集合扫描。

db.test_new_wildidx.find({"block.attr":{$exists:false}})

db.test_new_wildidx.find({"block.attr":{$exists:true}})  但是支持true的。

2.通配符索引不支持直接等于/不等于一个对象或者数组。

通配符索引会将对象或者数组中的元素加载到索引中,而不是整体放到索引中。故通配符索引不支持直接用文档或者数组来匹配。

所以上面的例子如果

7777:PRIMARY> db.test_new_wildidx.find({"block.attr.address_new": ["haicheng", "beijing", "chongqing"]})

就是想匹配整个数组的话,是不可能用到通配符索引的。

那么如果有这个需求该如何解决?Db.test_new_wildidx.createIndex({"block.attr.address_new":1}) 通过这个索引来解决。

虽然通配符索引不支持整个文档或者对象直接精准匹配查询,但是支持数组或者对象为空{} 这种操作:

7777:PRIMARY> db.test_new_wildidx.find({"block.attr": {}})
7777:PRIMARY> db.test_new_wildidx.find({"block.attr.address_new": {}})

3. 通配符索引支持如下索引类型或者或者属性:

Compound
TTL
Text
2d (Geospatial)
2dsphere (Geospatial)
Hashed
Unique

4.通配符索引不支持文档中的数组$ne null这种。其实不光是数组,别的字段也同样,只要是$ne都不会使用通配符索引。

5

总结

通配符索引在一定程度上可以应对在建模初期对于索引建立疏忽的遗漏,但是如果一味依赖通配符索引来解决查询中的各种精确字段的匹配那就是郑人买履了,在实际测试中通配符索引和精确字段的索引相比随着数据的增长效率逐渐下滑。这也是官方不是很建议使用通配符索引来替代常规索引的原因。

360云计算

由360云平台团队打造的技术分享公众号,内容涉及数据库、大数据、微服务、容器、AIOps、IoT等众多技术领域,通过夯实的技术积累和丰富的一线实战经验,为你带来最有料的技术分享

MongoDB通配符索引相关推荐

  1. Mongodb的索引操作

    Mongodb的索引操作 1. 为什么mongdb需要创建索引 加快查询速度 进行数据的去重 2. mongodb创建简单的索引方法 语法:db.集合名.ensureIndex({属性:1}),1表示 ...

  2. MongoDB复合索引详解

    摘要: 对于MongoDB的多键查询,创建复合索引可以有效提高性能. 什么是复合索引? 复合索引,即Compound Index,指的是将多个键组合到一起创建索引,这样可以加速匹配多个键的查询.不妨通 ...

  3. MongoDB数据库索引基础知识与实战技巧

    本文内容源自Kyle Banker 的MongoDB In Action一书.主要描述了MongoDB索引相关的一些基础知识和使用技巧. 索引类型 虽然MongoDB的索引在存储结构上都是一样的,但是 ...

  4. Mongodb的索引

    1. 简单介绍 索引是为了加速查询. 假设没有索引,mongodb在查询时会做表扫描,假设集合非常大时,这个查询会非常慢. 一般对创建查询时的键都建立索引. 为排序字段建立索引,假设对未建立索引的字段 ...

  5. 五、MongoDB的索引

    一.MongoDB的下载.安装与部署 二.MongoDB的基础知识简介 三.MongoDB的创建.更新和删除 四.MongoDB的查询 五.MongoDB的索引 1.简介 它就像是一本书的目录,如果没 ...

  6. mongodb及其索引的使用例子

    1.获取某个属性最大的value值并自增范例 因为mongo不支持类似select max操作,也不支持递增int的操作,所以采用目前的方案 #找到符合table_name的记录,find输出时只输出 ...

  7. mongo 唯一约束索引_快速掌握mongoDB(三)——mongoDB的索引详解

    1 mongoDB索引的管理 本节介绍mongoDB中的索引,熟悉mysql/sqlserver等关系型数据库的小伙伴应该都知道索引对优化数据查询的重要性.我们先简单了解一下索引:索引的本质就是一个排 ...

  8. MongoDB 教程索引 (附有视频)

    MongoDB 教程索引 MongoDB 教程一: 安装和使用 (Mongodb启动命令mongod参数说明) MongoDB 教程二: 添加, 删除,查询 shell命令 MongoDB 教程三: ...

  9. MongoDB 谨防索引seek的效率问题【华为云技术分享】

    目录 背景 初步分析 索引seeks的原因 优化思路 小结 声明:本文同步发表于 MongoDB 中文社区,传送门: http://www.mongoing.com/archives/27310 背景 ...

最新文章

  1. LeetCode03:无重复字符的最长子串
  2. 微软NNI-业内最亲民的AutoML工具学习笔记(1):AutoFeatureENG
  3. pycharm(windows)安装及其设置中文菜单
  4. 【干货】”首个“ .NET Core 验证码组件
  5. Win7\xp添加虚拟网Microsoft Loopback Adapter
  6. 【BZOJ1434】【codevs2348】染色游戏,博弈
  7. Apache Ranger——Hadoop ACL控制工具
  8. 关系查询处理 查询优化 论文_叮!你有一份留学论文攻略,请查收~
  9. Tensorflow:可视化学习TensorBoard
  10. 手机号码归属地查询接口大全
  11. INT 21H 指令说明及使用方法
  12. 【MPPT光伏】基于MPPT的光伏并网系统的simulink仿真
  13. Python中的numpy库介绍!
  14. Office Word 目录制作页码右对齐方法
  15. i5处理器做java够用吗,一般的游戏玩家用i5处理器就够了,这是真的吗?
  16. 小议费雪线性判别(Fisher Linear Discriminant Analysis)
  17. h5 bootstrap 小程序模板_汉中餐饮行业支付宝小程序模板
  18. 浅谈集合转换成数组的方法--toArray()与toArray(T[] a)
  19. 虎年啦,小老虎5分钟带你学会Linux中的移动-改名(mv)
  20. Github学生包申请流程

热门文章

  1. 面对挫折:给即将或已经遭受社会毒打的每一个人
  2. MyBatis多表查询(一对一,一对多,多对多)
  3. easyUI的combobox的实现
  4. Date型时间获取每周第一天,每月第一天,每季第一天,每年第一天
  5. 计算机键盘输入法基础知识,教程计算机基础知识-:认识输入法
  6. php打印预览jquery,php 实现打印预览的功能
  7. draggable禁止拖动_通过 JS 实现简单的拖拽功能并且可以在特定元素上禁止拖拽...
  8. Exploit开发系列教程-Exploitme2 (Stack cookies SEH)
  9. Mysql不能远程连接的解决方法
  10. unity 打包AssetBundle