关于MongoDB中对于Collection中的Array数组的注意事项
2017-04-09 12:17
381 查看
关于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 Array To 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 Criteria Use $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,如果需要精确查询,使用 { : } 格式。
希望能够对各位有所帮助,谢谢~
相关文章推荐
- 关于本地缓存localstorage与sessionStorage 数组 (array)字符串(string) 对象(object)的存储技巧和注意事项
- 关于本地缓存localstorage与sessionStorage 数组 (array)字符串(string) 对象(object)的存储技巧和注意事项
- js中数组(Array)的排序(sort)注意事项
- js中数组(Array)的排序(sort)注意事项
- js中数组(Array)的排序(sort)注意事项
- js中数组(Array)的排序(sort)注意事项说明
- mongodb对于数组基于位置的查找和修改注意点
- MongoDB--数据库与Collection注意事项
- 关于 MongoDB 与 SQL Server 通过本身自带工具实现数据快速迁移 及 注意事项 的探究
- php中array_unshift()修改数组key注意事项分析
- 关于MongoDB的几点注意事项
- 关于JAVA数组的几点注意事项与一些低级错误
- js中数组(Array)的排序(sort)注意事项
- php数组合并array_merge()函数使用注意事项
- 关于JAVA数组的几点注意事项与一些低级错误
- js中数组(Array)的排序(sort)注意事项 (转)
- 关于Java字符串数组的额外注意事项
- js中数组(Array)的排序(sort)注意事项
- OpenCV中关于InputArray、InputArrayOfArrays使用的注意事项
- 关于.Net数组的注意事项