概述
最近用到了 MongoDB 数组的一些操作符,如 $all
$elemMatch
所以研究一下,分享在这里
准备数据
数据如下
{ "_id" : { "$oid" : "6128e4c50990c143c05a8d29" }, "array" : [ 1, 2, 3 ], "name" : "hello" }
{ "_id" : { "$oid" : "6128e4cf0990c143c05a8d2a" }, "array" : [ 2, 3, 7 ], "name" : "world" }
{ "_id" : { "$oid" : "6128e4d80990c143c05a8d2b" }, "array" : [ 7, 15, 30 ], "name" : "java" }
{ "_id" : { "$oid" : "6128e4ef0990c143c05a8d2c" }, "array" : [ 25, 30, 49 ], "name" : "python" }
{ "_id" : { "$oid" : "6128e5000990c143c05a8d2d" }, "array" : [ 34, 48, 49 ], "name" : "c" }
{ "_id" : { "$oid" : "612a1ed50990c143c05a8d6b" }, "name" : "i-am-null" }
{ "_id" : { "$oid" : "612a1edf0990c143c05a8d6c" }, "name" : "i-am-empty", "array" : [ ] }
data
1. 『任意元素 eq』找到含有3的
没什么好说的,大家都会
db.getCollection("test-sytax").find({
array: 3
})
one
2. 『任意元素 匹配区间』找到含有 14 < x < 33
元素的文档
我们的需求是数组含有 15、16。。。30、31
,太多了,用表达式 $gt :14, $lt: 33
我们很快写出来了
db.getCollection("test-sytax").find({
array: {
$gt: 14,
$lt: 33
}
})
two
范围调整一下,试试查不到的情况,那就 11 < x < 15
吧,看下 数组含有 12、13、14
,应该是查不到的
db.getCollection("test-sytax").find({
array: {
$gt: 11,
$lt: 15
}
})
what?
什么情况?应该是匹配不到的呀
查阅官方文档,Query an Array
在 find
里对数组字段写多个条件,这些条件之间是 in
的关系,大家理解为 or
也没问题
那此时该怎么办呢? $elemMatch
就排上用场了, 官方文档为 elemMatch
The
$elemMatch
operator matches documents that contain an array field with at least one element that matches all the specified query criteria.
翻译过来就是: $elemMatch
操作符可以用来匹配指定数组
字段,包含有 至少一个
可以满足所有查询条件
的元素
我们试一下
db.getCollection("test-sytax").find({
array: {
$elemMatch: {
$gt: 11,
$lt: 15
}
}
})
empty
OK,此时返回为空,正常了
对比一下普通字段
对于数据
{ "_id" : { "$oid" : "612a32400990c143c05a8dc7" }, "age" : 1 }
{ "_id" : { "$oid" : "612a32430990c143c05a8dc8" }, "age" : 2 }
{ "_id" : { "$oid" : "612a32470990c143c05a8dc9" }, "age" : 3 }
and
可以看出:
对于普通字段,多个条件之间是 and 关系
对于数组字段,多个条件之间是 or 关系,如果想要达到 and 关系,需要使用 $elemMatch
3. 『数组 eq 指定数组』想要找的数组元素,一个不多,一个不少
对于数据
image.png
我知道有个文档的数组字段值就是 [ 1, 2, 3 ]
,现在把它找出来
现在写语句
db.getCollection("test-sytax").find({
array: {$in: [1,2,3]}
})
wrong
又不对了~
我们都知道还有个 $all
操作,现在来试试
db.getCollection("test-sytax").find({
array: {
$all: [1,2,3]
}
})
all
查阅文档 $all 得知
The
$all
operator selects the documents where the value of a field is an array that contains all the specified elements
翻译一下就是
$all
用在数组字段上,这个数字字段需要包含所有的指定元素
所以 $all
的参数其实是一个 子集
,作用就是找出包含这个子集的数组字段的文档
那么这里改怎么实现呢?在网上看到了一些回答,思路都是 数组字段不包含 1 2 3之外的元素
, 也就是 双重否定
来试一下
db.getCollection("test-sytax").find({
array: {
$not: {
$elemMatch: {
$nin: [1,2,3]
}
}
}
})
image.png
发现一些空的,还有其它类型的也都冒出来了,那么就再过滤一下
db.getCollection("test-sytax").find({
array: {
$not: {
$elemMatch: {
$nin: [1,2,3]
}
},
$type: 16
}
})
image.png
4. 『数组 all match』想要找的数组元素,所有元素都满足指定条件
对于数据
我们现在来找出
所有元素大于24的数组文档
, 也就是图中红框的两个文档
按照普通思路,上查询语句
db.getCollection("test-sytax").find({
array: {
$gt: 24
}
})
image.png
发现不对,还是按照 上面的 双重否定
思路来实现
db.getCollection("test-sytax").find({
array: {
$not: {
$elemMatch: {
$lte: 24
}
}
}
})
image.png
还是有一些干扰项,排除之
db.getCollection("test-sytax").find({
array: {
$not: {
$elemMatch: {
$lte: 24
}
},
$type: 16
}
})
image.png
总结下来:
allMatch
思路就是 双重否定
加 排除干扰项
总结
- 当
find
有多个条件时,如果字段是普通字段就是and
的关系; - 当
find
有多个条件时,如果是数组字段
就是or
的关系;想要数组字段达到and
的效果,需要使用$elemMatch
- 数组字段的操作符
$all
, 参数是指定子集
,作用是找出 所有包含这个子集的数组字段的文档 - MongoDB 本身没有提供
allMatch
, 需要自行实现,思路是双重否定
配合排除干扰项
参考
https://stackoverflow.com/questions/23595023/check-if-every-element-in-array-matches-condition
https://stackoverflow.com/questions/19574849/check-if-all-elements-in-mongodb-array-match-a-given-query
https://dba.stackexchange.com/questions/203042/mongodb-operator-to-match-arrays-whose-elements-are-all-contained-in-a-specifie
http://www.askasya.com/post/matchallarrayelements/
网友评论