Mongodb通配符索引签名和使用限制

学习mongodb,体会mongodb的每一个使用细节,欢迎阅读威赞的文章。这是威赞发布的第98篇mongodb技术文章,欢迎浏览本专栏威赞发布的其他文章。如果您认为我的文章对您有帮助或者解决您的问题,欢迎在文章下面点个赞,或者关注威赞。谢谢。威赞文章都是结合官方文档,翻译整理而来,并对每个知识点的描述都认真思考和实践,对难以理解的地方,使用简单容易理解的方式进行阐述。

Mongodb的通配符索引,为灵活的数据结构,提供了便利,但使用上有哪些限制?本文结合Mongodb的官方文档,总结了Mongodb通配符索引的使用和限制。

索引签名

自Mongodb5.0开始,通配符索引的wildcardProjection也会被包含到索引签名当中。索引签名,是识别索引唯一性的标志,包含了构建索引的各种参数。将通配符索引的wildcardProjection包含到索引当中,用户可以建立带有相同索引键但wildcardProjection不同的索引。如为集合books创建两个通配符索引。

db.books.createIndex({"$**": 1},{wildcardProjection: {"author.name": 1,"author.website": 1},name: "authorWildcard"
})db.books.createIndex({"$**": 1},{wildcardProjection: {"publisher.name": 1},name: "publisherWildcard"
})

查看索引

db.books.getIndexes()
[{"v": 2,"key": {"_id": 1},"name": "_id_"},{"v": 2,"key": {"$**": 1},"name": "authorWildcard","wildcardProjection": {"author.name": 1,"author.website": 1}},{"v": 2,"key": {"$**": 1},"name": "publisherWildcard","wildcardProjection": {"publisher.name": 1}}
]

两个索引都创建成功

通配符索引限制

复合通配符索引限制

  • 一个复合通配符索引只能包含一个通配符表达式,使用下面的表达式构建,是不可以的
{userID: 1, "object1.$**":1, "object2.$**":1}
  • 复合通配符索引当中,非通配符索引键不能使用多键索引键
  • 使用wildcardProjection选项时,构建索引的通配符只能时$**, 不能使用带有特殊路径的通配符表达式。下面的表达式是合法的
{key: { "$**:1"},name: "index_all_with_projection",wildcardProjection: {"someFields.name": 1,"otherFields.values": 1}
}

而带有字段的路径是不合法的

{key: { "someFields.$**:1"},name: "index_all_with_projection",wildcardProjection: {"someFields.name": 1,"otherFields.values": 1}
}
  • _id字段默认没有包含在通配符索引当中,如果用户构建的通配符索引需要包含_id字段,使用wildcardProjection指定包含_id字段。
db.studentGrades.createIndex({"$**": 1}, {wildcardProjection: {"grades": 1,"_id": 1}
})

唯一索引和过期时间

添加通配符索引时,不可指定唯一索引或索引过期时间。

空间索引与哈希

不能将通配符索引与空间索引和哈希索引合并创建通配符索引。

分片数据集

不能将通配符索引用来分片键当中。

通配符索引不支持的查询

数组字段不等于空的查询不支持

如在inventory集合中,字段production_attributes上构建了通配符索引。该通配符索引不支持数组字段的空值不等查询。如下面的查询,Mongodb编排查询计划时,不会使用通配符索引

db.inventory.find({$ne: ["product_attributes.tags", null]})
db.inventory.aggregate([{$match: { $ne: ["product_attributes.tags", null]}}
])

针对嵌入式文档和数组的精确查询

在构建通配符索引时,Mongodb将嵌入式文档和数组进行解析,将解析后的基本数据类型和其对应的字段路径加入到通配符索引当中,而不是将嵌入式文档和数组放入到通配符索引的结构当中。因此通配符索引,无法支持基于嵌入式文档和数组的精确查询。如针对inventory集合的查询,Mongodb在编排查询计划时,不会选择通配符索引。

db.inventory.find({"product_attributes": {"price": 29.99}}
)db.inventory.find({"product_attributes.tags": ["waterproof", "fireproof"]}
)

当然,通配符索引也不能够支持到嵌入式文档和数组的不等查询。

判断字段是否存在

通配符索引是稀疏的。当通配符索引指定的字段值在文档当中不存在时,文档数据不会加入到通配符索引当中。因此通配符索引不支持带有判断字段是否存在的查询。

如通配符索引不支持下面的几个查询

db.inventory.find({"product_attributes":  {$exists: false}}
)db.inventory.aggregate([{$match:  {"product_attributes": { $exists: false}}}
])

多字段查询

MongoDB不能使用非通配符索引来支持查询谓词的一部分而使用通配符索引来支持另一部分。

MongoDB不能在同一个查询中使用多个通配符索引来支持不同的谓词。

在一个通配符索引可以支持多个查询字段的情况下,MongoDB只能使用通配符索引来支持其中一个查询字段。MongoDB会根据对应的通配符索引路径自动选择通配符索引支持的字段。

db.inventory.find({"product_attributes.price": {$gt: 20},"product_attributes.material": "silk","product_attributes.size": "large"}
)

Mongodb通配符索引只能够支持查询条件中的一个条件。而选择哪个条件来使用通配符索引则与通配符索引的路径有关。

查看上面查询的执行计划

{"explainVersion": "2","queryPlanner": {"namespace": "test.inventory","indexFilterSet": false,"parsedQuery": {"$and": [{"product_attributes.material": {"$eq": "silk"}},{"product_attributes.size": {"$eq": "large"}},{"product_attributes.price": {"$gt": 20}}]},"queryHash": "03951C4C","planCacheKey": "BC3202F5","maxIndexedOrSolutionsReached": false,"maxIndexedAndSolutionsReached": false,"maxScansToExplodeReached": false,"winningPlan": {"queryPlan": {"stage": "FETCH","planNodeId": 2,"filter": {"$and": [{"product_attributes.price": {"$gt": 20}},{"product_attributes.size": {"$eq": "large"}}]},"inputStage": {"stage": "IXSCAN","planNodeId": 1,"keyPattern": {"$_path": 1,"product_attributes.material": 1},"indexName": "product_attributes.$**_1","isMultiKey": false,"multiKeyPaths": {"$_path": [],"product_attributes.material": []},"isUnique": false,"isSparse": true,"isPartial": false,"indexVersion": 2,"direction": "forward","indexBounds": {"$_path": ["[\"product_attributes.material\", \"product_attributes.material\"]"],"product_attributes.material": ["[\"silk\", \"silk\"]"]}}},"slotBasedPlan": {"slots": "$$RESULT=s11 env: { s14 = 20, s1 = TimeZoneDatabase(America/Argentina/La_Rioja...Asia/Ashkhabad) (timeZoneDB), s10 = {\"$_path\" : 1, \"product_attributes.material\" : 1}, s6 = KS(3C70726F647563745F617474726962757465732E6D6174657269616C003C73696C6B00FE04), s15 = \"large\", s3 = 1721879566202 (NOW), s2 = Nothing (SEARCH_META), s5 = KS(3C70726F647563745F617474726962757465732E6D6174657269616C003C73696C6B000104) }","stages": "[2] filter {(traverseF(s13, lambda(l1.0) { traverseF(getField(l1.0, \"price\"), lambda(l2.0) { ((l2.0 > s14) ?: false) }, false) }, false) && traverseF(s13, lambda(l3.0) { traverseF(getField(l3.0, \"size\"), lambda(l4.0) { ((l4.0 == s15) ?: false) }, false) }, false))} \n[2] nlj inner [] [s4, s7, s8, s9, s10] \n    left \n        [1] cfilter {(exists(s5) && exists(s6))} \n        [1] ixseek s5 s6 s9 s4 s7 s8 [] @\"259baef3-1faf-4703-8a12-870b2c7e1f55\" @\"product_attributes.$**_1\" true \n    right \n        [2] limit 1 \n        [2] seek s4 s11 s12 s7 s8 s9 s10 [s13 = product_attributes] @\"259baef3-1faf-4703-8a12-870b2c7e1f55\" true false \n"}},"rejectedPlans": [{"queryPlan": {"stage": "FETCH","planNodeId": 2,"filter": {"$and": [{"product_attributes.material": {"$eq": "silk"}},{"product_attributes.size": {"$eq": "large"}}]},"inputStage": {"stage": "IXSCAN","planNodeId": 1,"keyPattern": {"$_path": 1,"product_attributes.price": 1},"indexName": "product_attributes.$**_1","isMultiKey": false,"multiKeyPaths": {"$_path": [],"product_attributes.price": []},"isUnique": false,"isSparse": true,"isPartial": false,"indexVersion": 2,"direction": "forward","indexBounds": {"$_path": ["[\"product_attributes.price\", \"product_attributes.price\"]"],"product_attributes.price": ["(20, inf.0]"]}}},"slotBasedPlan": {"slots": "$$RESULT=s11 env: { s14 = \"silk\", s10 = {\"$_path\" : 1, \"product_attributes.price\" : 1}, s1 = TimeZoneDatabase(America/Argentina/La_Rioja...Asia/Ashkhabad) (timeZoneDB), s15 = \"large\", s6 = KS(3C70726F647563745F617474726962757465732E70726963650033FFFFFFFFFFFFFFFFFE04), s3 = 1721879566202 (NOW), s5 = KS(3C70726F647563745F617474726962757465732E7072696365002B28FE04), s2 = Nothing (SEARCH_META) }","stages": "[2] filter {(traverseF(s13, lambda(l1.0) { traverseF(getField(l1.0, \"material\"), lambda(l2.0) { ((l2.0 == s14) ?: false) }, false) }, false) && traverseF(s13, lambda(l3.0) { traverseF(getField(l3.0, \"size\"), lambda(l4.0) { ((l4.0 == s15) ?: false) }, false) }, false))} \n[2] nlj inner [] [s4, s7, s8, s9, s10] \n    left \n        [1] cfilter {(exists(s5) && exists(s6))} \n        [1] ixseek s5 s6 s9 s4 s7 s8 [] @\"259baef3-1faf-4703-8a12-870b2c7e1f55\" @\"product_attributes.$**_1\" true \n    right \n        [2] limit 1 \n        [2] seek s4 s11 s12 s7 s8 s9 s10 [s13 = product_attributes] @\"259baef3-1faf-4703-8a12-870b2c7e1f55\" true false \n"}},{"queryPlan": {"stage": "FETCH","planNodeId": 2,"filter": {"$and": [{"product_attributes.material": {"$eq": "silk"}},{"product_attributes.price": {"$gt": 20}}]},"inputStage": {"stage": "IXSCAN","planNodeId": 1,"keyPattern": {"$_path": 1,"product_attributes.size": 1},"indexName": "product_attributes.$**_1","isMultiKey": false,"multiKeyPaths": {"$_path": [],"product_attributes.size": []},"isUnique": false,"isSparse": true,"isPartial": false,"indexVersion": 2,"direction": "forward","indexBounds": {"$_path": ["[\"product_attributes.size\", \"product_attributes.size\"]"],"product_attributes.size": ["[\"large\", \"large\"]"]}}},"slotBasedPlan": {"slots": "$$RESULT=s11 env: { s14 = \"silk\", s10 = {\"$_path\" : 1, \"product_attributes.size\" : 1}, s1 = TimeZoneDatabase(America/Argentina/La_Rioja...Asia/Ashkhabad) (timeZoneDB), s15 = 20, s6 = KS(3C70726F647563745F617474726962757465732E73697A65003C6C6172676500FE04), s3 = 1721879566202 (NOW), s5 = KS(3C70726F647563745F617474726962757465732E73697A65003C6C61726765000104), s2 = Nothing (SEARCH_META) }","stages": "[2] filter {(traverseF(s13, lambda(l1.0) { traverseF(getField(l1.0, \"material\"), lambda(l2.0) { ((l2.0 == s14) ?: false) }, false) }, false) && traverseF(s13, lambda(l3.0) { traverseF(getField(l3.0, \"price\"), lambda(l4.0) { ((l4.0 > s15) ?: false) }, false) }, false))} \n[2] nlj inner [] [s4, s7, s8, s9, s10] \n    left \n        [1] cfilter {(exists(s5) && exists(s6))} \n        [1] ixseek s5 s6 s9 s4 s7 s8 [] @\"259baef3-1faf-4703-8a12-870b2c7e1f55\" @\"product_attributes.$**_1\" true \n    right \n        [2] limit 1 \n        [2] seek s4 s11 s12 s7 s8 s9 s10 [s13 = product_attributes] @\"259baef3-1faf-4703-8a12-870b2c7e1f55\" true false \n"}}]},"command": {"find": "inventory","filter": {"product_attributes.price": {"$gt": 20},"product_attributes.material": "silk","product_attributes.size": "large"},"$db": "test"},"serverInfo": {"host": "TEST-W11","port": 27017,"version": "7.0.4","gitVersion": "38f3e37057a43d2e9f41a39142681a76062d582e"},"serverParameters": {"internalQueryFacetBufferSizeBytes": 104857600,"internalQueryFacetMaxOutputDocSizeBytes": 104857600,"internalLookupStageIntermediateDocumentMaxSizeBytes": 104857600,"internalDocumentSourceGroupMaxMemoryBytes": 104857600,"internalQueryMaxBlockingSortMemoryUsageBytes": 104857600,"internalQueryProhibitBlockingMergeOnMongoS": 0,"internalQueryMaxAddToSetBytes": 104857600,"internalDocumentSourceSetWindowFieldsMaxMemoryBytes": 104857600,"internalQueryFrameworkControl": "trySbeEngine"},"ok": 1
}

查询排序

通配符查询仅支持索引覆盖查询的排序。排序字段还不能是数组。

如在集合product的product_attributes构建通配符索引

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

当price字段不是数组时,通配符索引可以支持该排序查询

db.products.find({"product_attributes.price": { $gt: 10.00}} 
).sort({"product_attributes.price": 1} )

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/50793.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ArcGIS Pro SDK (九)几何 15 转换

ArcGIS Pro SDK (九)几何 15 转换 文章目录 ArcGIS Pro SDK (九)几何 15 转换1 创建地理转换2 创建复合地理变换3 创建投影转换4 创建高压基准变换5 创建复合高压基准变换6 决定转换7 地图点 - 地理坐标字符串转换 环境&#xff1…

构建现代化农业产业服务平台的系统架构

随着全球农业产业的发展和技术的进步,农业生产管理面临着越来越复杂的挑战和机遇。建立一个现代化的农业产业服务平台系统架构,不仅能够提高农业生产效率和管理水平,还能促进农民收入增长和可持续发展。本文将探讨如何设计和实施这样一个系统…

【计算机网络】期末实验答辩

注意事项: 1)每位同学要在下面做过的实验列表中选取三个实验进行答辩准备,并将自己的姓名,学号以及三个实验序号填入共享文档"1(2)班答辩名单"中。 2)在答辩当日每位同学由老师在表…

C# 使用pythonnet 迁入 python 初始化错误解决办法

pythonnet 从 3.0 版本开始,必须设置Runtime.PythonDLL属性或环境变量 例如: string pathToVirtualEnv ".\\envs\\pythonnetTest"; Runtime.PythonDLL Path.Combine(pathToVirtualEnv, "python39.dll"); PythonEngine.PythonHom…

vue路由跳转时改变路由参数组件不渲染问题【已解决】

效果展示 解决 router路由为了组件复用,防止组件的频繁销毁与创建,在遇到跳转的路由不一致才会进行重新渲染,路径参数变了他是不会管的,只会改变this.$route对象而已 就这个东西/:xxx 我们可以写一个watch监视this.$route对象。…

SQL语句(以MySQL为例)——单表、多表查询

笛卡尔积(或交叉连接): 笛卡尔乘积是一个数学运算。假设我有两个集合 X 和 Y,那么 X 和 Y 的笛卡尔积就是 X 和 Y 的所有可能组合,也就是第一个对象来自于 X,第二个对象来自于 Y 的所有可能。组合的个数即为两个集合中…

python爬虫-事件触发机制

今天想爬取一些政策,从政策服务 (smejs.cn) 这个网址爬取,html源码找不到链接地址,通过浏览器的开发者工具,点击以下红框 分析预览可知想要的链接地址的id有了,进行地址拼接就行 点击标头可以看到请求后端服务器的api地…

GraphHopper路径规划导航(Android源码调试运行)

本文主要记录在运行graphhopper安卓版路径规划导航源码的步骤和遇到的问题。 成功运行了程序,但是路劲规划一直不成功,问题一开始是服务地址,后来又是key的问题,在这个项目中涉及到了graphhopper、mapbox、mapilion的key&#xff…

html+css+js 实现马赛克背景按钮

前言:哈喽,大家好,今天给大家分享htmlcss 绚丽效果!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 文…

前端练习<HtmlCSS>——照片墙(附完整代码及实现效果)

这个小练习也来源于b站up小K师兄,大家可以通过下面的链接学习哦~up讲的非常详细。 纯CSS写一个简单酷炫的照片墙效果~ 先看一下这个照片墙的效果: 1.鼠标没有放到图片上时,照片同比例,每张照片都有倒影的效果。 2.然…

生成式AI和LLM的革命:Transformer架构

近年来,随着一篇名为“Attention is All You Need”论文的出现,自然语言处理(NLP)领域经历了一场巨大的变革。2017年,在谷歌和多伦多大学发表了这篇论文后,Transformer架构出现了。这一架构不仅显著提升了N…

Spring RestTemplate:简化HTTP请求的利器

在现代Web开发中,HTTP请求是与外部服务交互的主要方式之一。Spring框架提供的RestTemplate工具,大大简化了HTTP请求的发送和处理过程,让开发者可以更加专注于业务逻辑的实现。本文将带你了解RestTemplate的基本用法及其在实际项目中的配置方法…

【BUG】已解决:ERROR: Failed building wheel for jupyter-nbextensions-configurator

ERROR: Failed building wheel for jupyter-nbextensions-configurator 目录 ERROR: Failed building wheel for jupyter-nbextensions-configurator 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页,我…

第 3 章 数据和 C

目录 3.1 示例程序 3.1.1 程序中的新元素 3.2 变量与常量数据 3.3 数据: 数据类型关键字 3.3.1 整数和浮点数 3.3.2 整数 3.3.3 浮点数 3.4 C 语言基本数据类型 3.4.1 int 类型 1. 声明 int 变量 2. 初始化变量 3. int 类型常量 4. 打印 int 值 5. 八进制和十六进…

测试面试中遇到的python题目

1、九九乘法表 #九九乘法表 for i in range(1, 10): #range函数是左开右闭for j in range(1, i1):result j * iprint(%d*%d%d%(j,i,result), end" ") #print打印会默认换行,end 意思是末尾不换行,加空格print() #换行2、100-10000之间&#x…

Linux I2C驱动程序

Linux I2C驱动 前言 主要目的记录一下我在野火的i.MX6ULL mini开发板上面编写了一个Linux I2C设备驱动去驱动SSD1306 OLED屏幕的开发过程。源码用的是野火提供的内核源码。 SSD1306 OLED和I2C接口 这块OLED屏幕大家应该都比较熟悉了,小巧迷你,DIY很好…

习题2.24

没啥好说, 先看解释器给出的结果 说起来也简单,这是一个多层的列表,第一个元素是1 第二个元素是(2 ( 3 4)) 第二层第一个是2 第二个是 (3 4) 第三层第一个是 3 第二个…

项目中自定义python异常类

作为一个初学者 ,在github上看到一个项目中异常文件,我也不知道当时为什么这么写,越来越觉得写得是不是有问题,所以我先写一遍我认为是对的,在看一下那个项目怎么写的以及我为什么 认为有问题 首先定义异常基类 cla…

stm32入门-----ADC模数转换器(理论篇——上)

目录 前言 一、ADC模数转换器 1.简介 2.ADC的结构 3.输入通道 4.转换模式 5.触发控制 6.数据对齐 7.转换时间 8.校准 前言 本期就开始学习ADC模数转换器,这个大家在学习51单片机的时候应该就接触过了,实际上就是把模拟电压转换为…

YOLOv5改进 | 卷积模块 | 即插即用的递归门控卷积gnConv

秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 专栏目录: 《YOLOv5入门 改…