指南
MongoDB在4.2 版本推出了Wildcard Indexes,究竟什么是Wildcard Indexes以及Wildcard Indexes适合哪些场景本文结合官方文档以及实际测试进行简单概述。
1、通配符索引示例
因为MongoDB是dynamic schemas,所以应用是可以查询任何已知字段或者随机字段的。
假设(此假设案例摘自官方文档),集合colA的UserMetadata字段包含如下数据:
{ "userMetadata" : { "likes" : [ "dogs", "cats" ] } } { "userMetadata" : { "dislikes" : "pickles" } } { "userMetadata" : { "age" : 45 } } { "userMetadata" : "inactive" }
但是在查询的时候可能是如下语句:
db.colA.find({ "userMeta2 通配符索引的形式data.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、总结
通配符索引在一定程度上可以应对在建模初期对于索引建立疏忽的遗漏,但是如果一味依赖通配符索引来解决查询中的各种精确字段的匹配那就是郑人买履了,在实际测试中通配符索引和精确字段的索引相比随着数据的增长效率逐渐下滑。这也是官方不是很建议使用通配符索引来替代常规索引的原因。
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 小骆驼-《草原狼2(蓝光CD)》[原抓WAV+CUE]
- 群星《欢迎来到我身边 电影原声专辑》[320K/MP3][105.02MB]
- 群星《欢迎来到我身边 电影原声专辑》[FLAC/分轨][480.9MB]
- 雷婷《梦里蓝天HQⅡ》 2023头版限量编号低速原抓[WAV+CUE][463M]
- 群星《2024好听新歌42》AI调整音效【WAV分轨】
- 王思雨-《思念陪着鸿雁飞》WAV
- 王思雨《喜马拉雅HQ》头版限量编号[WAV+CUE]
- 李健《无时无刻》[WAV+CUE][590M]
- 陈奕迅《酝酿》[WAV分轨][502M]
- 卓依婷《化蝶》2CD[WAV+CUE][1.1G]
- 群星《吉他王(黑胶CD)》[WAV+CUE]
- 齐秦《穿乐(穿越)》[WAV+CUE]
- 发烧珍品《数位CD音响测试-动向效果(九)》【WAV+CUE】
- 邝美云《邝美云精装歌集》[DSF][1.6G]
- 吕方《爱一回伤一回》[WAV+CUE][454M]