关于MongoDB中对于Collection中的Array数组的注意事项
来源:互联网 发布:日程软件 知乎 电脑 编辑:程序博客网 时间:2024/05/17 21:43
关于MongoDB中对于Collection中的Array数组的注意事项
前两天在工作中遇到一个对mongoDB的Collection中Array数组查询的问题,百思不得其解之后豁然开朗,今天给大家分享一下。
当时遇到的问题是,我现在有两个文档,其结构分别为:
{"_id" : ObjectId("58e88fa90cf2b631bab2f0d8"),"title" : "A","places" : [ { "placeId" : "58d24465f323560340686c1a", "sourceType" : "articlePlace", "status":1 }, { "placeId" : "58de05f10cf2c09e03c3542b", "sourceType" : "travelPlace", "status":1 }],"status" : 1}{"_id" : ObjectId("58e89caaf323560340686c31"),"title" : "B","places" : [ { "placeId" : "58d24465f323560340686c1a", "sourceType" : "articlePlace", "status":1 }, { "placeId" : "58de05f10cf2c09e03c3542b", "sourceType" : "articlePlace", "status":1 }],"status" : 1}
文档A和文档B中都有一个places数组,其中placeId为58de05f10cf2c09e03c3542b在两个文档中都有,但是这两个的sourceType又分别不同,现在,我需要将placeId为58de05f10cf2c09e03c3542b,同时对应的sourceType为travelPlace的文档A给筛选出来。
遇到这个问题的时候,首先,我的查询语句是这个样子的:
db.getCollection('test').find({"places.placeId":"58de05f10cf2c09e03c3542b","places.sourceType":"travelPlace"})
结果如下所示:
{"_id" : ObjectId("58e88fa90cf2b631bab2f0d8"),"title" : "A","places" : [ { "placeId" : "58d24465f323560340686c1a", "sourceType" : "articlePlace", "status":1 }, { "placeId" : "58de05f10cf2c09e03c3542b", "sourceType" : "travelPlace", "status":1 }],"status" : 1}
看起来应该是正确的,但是当我变更一下query语句之后:
db.getCollection('test').find({"places.placeId":"58de05f10cf2c09e03c3542b","places.sourceType":"articlePlace"})
结果出来是:
{"_id" : ObjectId("58e88fa90cf2b631bab2f0d8"),"title" : "A","places" : [ { "placeId" : "58d24465f323560340686c1a", "sourceType" : "articlePlace", "status":1 }, { "placeId" : "58de05f10cf2c09e03c3542b", "sourceType" : "travelPlace", "status":1 }],"status" : 1}{"_id" : ObjectId("58e89caaf323560340686c31"),"title" : "B","places" : [ { "placeId" : "58d24465f323560340686c1a", "sourceType" : "articlePlace", "status":1 }, { "placeId" : "58de05f10cf2c09e03c3542b", "sourceType" : "articlePlace", "status":1 }],"status" : 1}
两个文档都被查询出来了!what?为什么会命中两个记录?
我们来分析一下查询语句:
db.getCollection('test').find({"places.placeId":"58de05f10cf2c09e03c3542b","places.sourceType":"articlePlace"})
这条语句有两个条件:
- 查询出所有places.placeId为58de05f10cf2c09e03c3542b的文档;
- 查询出所有places.sourceType为articlePlace的文档
这两个条件组合在一起之后,其执行过程是:
- 首先找出所有places.placeId等于58de05f10cf2c09e03c3542b的文档,命中文档A和文档B,原因是文档A中places子集中有一个placeId为58de05f10cf2c09e03c3542b,sourceType为travelPlace的文档,所以命中文档A,文档B中同样存在一个placeId为58de05f10cf2c09e03c3542b的文档子集;
- 然后找出所有places.sourceType等于articlePlace的文档,其命中结果也是文档A和文档B,它的逻辑是文档A中有一个placeId为58d24465f323560340686c1a,sourceType为articlePlace的子集,文档B中有两个sourceType为articlePlace,placeId不同的文档子集;
- 将两个结果合并取交集;
我们可以看到,此时query语句对于places数组文档的操作粒度是基于整个文档的,对两个约束条件的交集,而不是对每一个文档的places子文档集的交集;
在此我们可以打一个比方:我有一百块钱预算,我先去便利店买个一百的商品A、A,然后我回家了,第二次我又去便利店买了一百的东西B、B,然后我又回家了,到家之后我把两次购买的商品放到一起,发现总商品价值两百元,超支了!我原有的计划是在AB两种商品中挑选一种,然后只花一百块钱。结果我买了两次,然后每次都买了一百,结果就错了。
既然发现了问题,下面我们要解决的就是如何在一次约束条件中完成对子文档列表的整个查询约束,我把原有的查询条件变更为下面这种形式:
db.getCollection('test').find({"places":{"placeId":"58de05f10cf2c09e03c3542b","sourceType":"articlePlace"}})
现在的条件是:对places进行一次查询,约束条件为placeId等于58de05f10cf2c09e03c3542b,sourceType等于articlePlace;
执行之后发现,没有返回任何结果!Why?查看官方文档中对关于”Query a Array”的描述中有这样一段话:
Match an ArrayTo specify equality condition on an array, use the query document { <field>: <value> } where <value> is the exact array to match, including the order of the elements.
原来通过这种{:}的操作需要后面的value是和array中子集完全匹配,可是对于Array中的子集,实际项目中可能还会有很多其他的内容,这些可能各不相同,如果要精确查询,最后只能得到一个准确的值,不符合我们的需要。我们需要对一个array子集进行多重符合条件的查询,但是又需要忽略那些不必要的元素,最后没办法,只能祭出杀手锏—-看官方API。
Query for an Array Element that Meets Multiple CriteriaUse $elemMatch operator to specify multiple criteria on the elements of an array such that at least one array element satisfies all the specified criteria.
原来当我们需要对array子集进行多重符合查询语句时,需要使用$elemMacth查询条件,这样,我们的Query语句最终变为这样:
db.getCollection('test').find({"places":{$elemMatch:{"placeId":"58de05f10cf2c09e03c3542b","sourceType":"articlePlace"}}})
执行后结果:
{"_id" : ObjectId("58e89caaf323560340686c31"),"title" : "B","places" : [ { "placeId" : "58d24465f323560340686c1a", "sourceType" : "articlePlace", "status" : 1 }, { "placeId" : "58de05f10cf2c09e03c3542b", "sourceType" : "articlePlace", "status" : 1 }],"status" : 1}
get!我们再换一下sourceType:
db.getCollection('test').find({"places":{$elemMatch:{"placeId":"58de05f10cf2c09e03c3542b","sourceType":"travelPlace"}}})
执行结果:
{"_id" : ObjectId("58e88fa90cf2b631bab2f0d8"),"title" : "A","places" : [ { "placeId" : "58d24465f323560340686c1a", "sourceType" : "articlePlace", "status" : 1 }, { "placeId" : "58de05f10cf2c09e03c3542b", "sourceType" : "travelPlace", "status" : 1 }],"status" : 1}
如果需要对Collection的Array子集进行整体性地复合查询,需要使用$elemMatch,如果需要精确查询,使用 { : } 格式。
希望能够对各位有所帮助,谢谢~
- 关于MongoDB中对于Collection中的Array数组的注意事项
- 关于mongodb的 数组分组 array group
- js中数组(Array)的排序(sort)注意事项 (转)
- js中数组(Array)的排序(sort)注意事项
- js中数组(Array)的排序(sort)注意事项
- js中数组(Array)的排序(sort)注意事项
- js中数组(Array)的排序(sort)注意事项说明
- spring-data-mongodb 对于collection的upsert操作
- MongoDB--数据库与Collection注意事项
- Java中取得数组(array),集合(Collection)和字符串(String)的长度
- as3中Array与Collection的区别
- 对于程序中变量定义的注意事项
- 关于MongoDB的几点注意事项
- 关于.Net数组的注意事项
- 遍历collection的注意事项
- 关于本地缓存localstorage与sessionStorage 数组 (array)字符串(string) 对象(object)的存储技巧和注意事项
- 关于本地缓存localstorage与sessionStorage 数组 (array)字符串(string) 对象(object)的存储技巧和注意事项
- 对于Array的引用
- linux基础2-6文本处理工具
- ubiqua 2.0 破解版 zigbee 协议分析软件加密与验证机制,破解可行性的思考
- Python(8):关于绘图
- linux基础2-9vsftpd服务
- 垃圾收集算法与内存分配策略--《深入理解Java虚拟机》学习笔记
- 关于MongoDB中对于Collection中的Array数组的注意事项
- JAVA集合类汇总
- HotSpot 调试环境搭建
- 用Java实现求一个数组中的出现次数最多的元素的个数
- Ubuntu进入root账户失败,重新更改root密码
- 浅谈死锁
- 深入理解计算机系统(CSAPP)课程实验bomb程序炸弹实验日志(phase_5)
- 驾驶证识别,OCR识别技术共同推进人工智能
- Android上手机软件调用外部地图软件