美文网首页
MongoDB 查询技巧(3) - 数组操作

MongoDB 查询技巧(3) - 数组操作

作者: Yellowtail | 来源:发表于2021-08-31 09:09 被阅读0次

概述

最近用到了 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』想要找的数组元素,所有元素都满足指定条件

对于数据

image.png
我们现在来找出 所有元素大于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 思路就是 双重否定 加 排除干扰项

总结

  1. find有多个条件时,如果字段是普通字段就是and的关系;
  2. find有多个条件时,如果是数组字段就是 or 的关系;想要数组字段达到and的效果,需要使用$elemMatch
  3. 数组字段的操作符 $all, 参数是指定子集,作用是找出 所有包含这个子集的数组字段的文档
  4. 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/

相关文章

网友评论

      本文标题:MongoDB 查询技巧(3) - 数组操作

      本文链接:https://www.haomeiwen.com/subject/zzciiltx.html