MongoDB聚合管道数组操作

数组表达式运算符判断数组中是否包含元素( i n ) 并获取元素索引 ( in)并获取元素索引( in)并获取元素索引(indexOfArray)

一、初始化成员数据

plain 复制代码
db.persons.insertMany([
    { "_id" : "1001", "name" : "张三", "fruits" : [ "apple", "orange" ] },
    { "_id" : "1002", "name" : "李四", "fruits" : [ "banana", "apple" ] },
    { "_id" : "1003", "name" : "王五", "fruits" : [ "banana", "apple", "orange" ] },
    { "_id" : "1004", "name" : "赵六", "fruits" : [ ] },
    { "_id" : "1005", "name" : "田七" },
])

二、包含元素($in)

语法:{ $in: [ , ] }

判断数组中是否包含某个元素

expression:代表的是元素

array expression:代表的是数组

例子:判断成员是否喜欢苹果

plain 复制代码
db.persons.aggregate([
    {
        $project: {
            "name": 1,
            "favoriteApple": {
                $in: [ "apple", "$fruits" ]
            }
        }
    }
])

聚合查询的结果如下:

plain 复制代码
{
	"ok" : 0,
	"errmsg" : "$in requires an array as a second argument, found: missing",
	"code" : 40081,
	"codeName" : "Location40081"
}

发现报错了,原因是在编号为1005的成员中不存在fruits字段导致的。

这里我们需要**使用 i s A r r a y 断言数组操作进行聚合查询 < / f o n t > ∗ ∗ < f o n t s t y l e = " c o l o r : r g b ( 77 , 77 , 77 ) ; " > ,如果您对 isArray断言数组操作进行聚合查询</font>**<font style="color:rgb(77, 77, 77);">,如果您对 isArray断言数组操作进行聚合查询</font>∗∗<fontstyle="color:rgb(77,77,77);">,如果您对isArray断言数组操作不太了解,可以参考:https://blog.csdn.net/m1729339749/article/details/130162535

下面我们使用$isArray断言数组操作改进聚合查询:

plain 复制代码
db.persons.aggregate([
    {
        $project: {
            "name": 1,
            "favoriteApple": {
                $cond: {
                    if: { $isArray: "$fruits" }, 
                    then: { $in: [ "apple", "$fruits" ] }, 
                    else: false
                }
            }
        }
    }
])

聚合查询的结果如下:

plain 复制代码
{ "_id" : "1001", "name" : "张三", "favoriteApple" : true }
{ "_id" : "1002", "name" : "李四", "favoriteApple" : true }
{ "_id" : "1003", "name" : "王五", "favoriteApple" : true }
{ "_id" : "1004", "name" : "赵六", "favoriteApple" : false }
{ "_id" : "1005", "name" : "田七", "favoriteApple" : false }

三、获取元素索引($indexOfArray)

语法:{ $indexOfArray: [ , , , ] }

查询元素在数组中的索引位置

array expression:代表的是数组

search expression:代表的是待搜索的元素

start:可选,搜索的起始位置

end:可选,搜索的结束位置

搜索的范围是 [start, end) 即前开后闭

例子1:搜索水果apple的索引

plain 复制代码
db.persons.aggregate([
    {
        $project: {
            "name": 1,
            "indexApple": {
                $indexOfArray: [ "$fruits", "apple" ]
            }
        }
    }
])

聚合查询的结果如下:

plain 复制代码
{ "_id" : "1001", "name" : "张三", "indexApple" : 0 }
{ "_id" : "1002", "name" : "李四", "indexApple" : 1 }
{ "_id" : "1003", "name" : "王五", "indexApple" : 1 }
{ "_id" : "1004", "name" : "赵六", "indexApple" : -1 }
{ "_id" : "1005", "name" : "田七", "indexApple" : null }

未查找到元素,返回-1

数组字段不存在,返回null

例子2:搜索水果apple的索引,起始位置(0)结束位置(1)

plain 复制代码
db.persons.aggregate([
    {
        $project: {
            "name": 1,
            "indexApple": {
                $indexOfArray: [ "$fruits", "apple", 0 ,1 ]
            }
        }
    }
])

聚合查询的结果如下:

bash 复制代码
{ "_id" : "1001", "name" : "张三", "indexApple" : 0 }
{ "_id" : "1002", "name" : "李四", "indexApple" : -1 }
{ "_id" : "1003", "name" : "王五", "indexApple" : -1 }
{ "_id" : "1004", "name" : "赵六", "indexApple" : -1 }
{ "_id" : "1005", "name" : "田七", "indexApple" : null }

与例子1中聚合查询的结果比较我们会发现:

编号为1002,1003的成员数据中没有检索到元素,说明检索的范围不包含结束位置对应的索引。

start,end检索的范围是[start, end),包含起始位置对应的索引,不包含结束位置对应的索引

数组表达式运算符截取数组($slice)

数组表达式运算符主要用于文档中数组的操作,本篇我们主要介绍数组表达式运算符中用于截取数组的操作,下面我们进行详细介绍:

一、语法

{ $slice: [ , ] }

或者 { $slice: [ , , ] }

获取数组中指定范围内的元素组成一个新的数组

:代表的是数组

:代表的是起始位置索引(包含此位置的元素)

:代表的是获取N个元素

二、准备工作

初始化成员数据

bash 复制代码
db.persons.insertMany([
    { "_id" : "1001", "name" : "张三", "fruits" : [ "apple", "pineapple", "orange" ] },
    { "_id" : "1002", "name" : "李四", "fruits" : [ "banana", "apple", "pineapple" ] },
    { "_id" : "1003", "name" : "王五", "fruits" : [ "banana", "apple", "orange", "watermelon" ] },
    { "_id" : "1004", "name" : "赵六", "fruits" : [ ] },
    { "_id" : "1005", "name" : "田七" },
])

三、示例

例子1:找到每个人最喜欢吃的前两个水果

bash 复制代码
db.persons.aggregate([
    {
        $project: {
            "name": 1,
            "favoriteFruits": { $slice: [ "$fruits", 2 ] }
        }
    }
])

聚合查询的结果如下:

bash 复制代码
{ "_id" : "1001", "name" : "张三", "favoriteFruits" : [ "apple", "pineapple" ] }
{ "_id" : "1002", "name" : "李四", "favoriteFruits" : [ "banana", "apple" ] }
{ "_id" : "1003", "name" : "王五", "favoriteFruits" : [ "banana", "apple" ] }
{ "_id" : "1004", "name" : "赵六", "favoriteFruits" : [ ] }
{ "_id" : "1005", "name" : "田七", "favoriteFruits" : null }

例子2:找到每个人最喜欢吃的最后两个水果

bash 复制代码
db.persons.aggregate([
    {
        $project: {
            "name": 1,
            "favoriteFruits": { $slice: [ "$fruits", -2 ] }
        }
    }
])

聚合查询的结果如下:

bash 复制代码
{ "_id" : "1001", "name" : "张三", "favoriteFruits" : [ "pineapple", "orange" ] }
{ "_id" : "1002", "name" : "李四", "favoriteFruits" : [ "apple", "pineapple" ] }
{ "_id" : "1003", "name" : "王五", "favoriteFruits" : [ "orange", "watermelon" ] }
{ "_id" : "1004", "name" : "赵六", "favoriteFruits" : [ ] }
{ "_id" : "1005", "name" : "田七", "favoriteFruits" : null }

(1)****字段未定义时,结果为null;

(2)未找到元素,结果为[ ]

(3){ $slice: [ , ] } 语法中 n为正数,代表的是从前往后取N个元素,n为负数,代表的是从后往前取N个元素

例子3:找到每个人最喜欢吃的第二个水果

bash 复制代码
db.persons.aggregate([
    {
        $project: {
            "name": 1,
            "favoriteFruits": { $slice: [ "$fruits", 1, 1 ] }
        }
    }
])

聚合查询的结果如下:

bash 复制代码
{ "_id" : "1001", "name" : "张三", "favoriteFruits" : [ "pineapple" ] }
{ "_id" : "1002", "name" : "李四", "favoriteFruits" : [ "apple" ] }
{ "_id" : "1003", "name" : "王五", "favoriteFruits" : [ "apple" ] }
{ "_id" : "1004", "name" : "赵六", "favoriteFruits" : [ ] }
{ "_id" : "1005", "name" : "田七", "favoriteFruits" : null }

例子4:假如position为负数,会如何处理

bash 复制代码
db.persons.aggregate([
    {
        $project: {
            "name": 1,
            "favoriteFruits": { $slice: [ "$fruits", -2, 1 ] }
        }
    }
])

聚合查询的结果如下:

bash 复制代码
{ "_id" : "1001", "name" : "张三", "favoriteFruits" : [ "pineapple" ] }
{ "_id" : "1002", "name" : "李四", "favoriteFruits" : [ "apple" ] }
{ "_id" : "1003", "name" : "王五", "favoriteFruits" : [ "orange" ] }
{ "_id" : "1004", "name" : "赵六", "favoriteFruits" : [ ] }
{ "_id" : "1005", "name" : "田七", "favoriteFruits" : null }

例子5:假如position = -10,会如何处理

bash 复制代码
db.persons.aggregate([
    {
        $project: {
            "name": 1,
            "favoriteFruits": { $slice: [ "$fruits", -10, 1 ] }
        }
    }
])

聚合查询的结果如下:

bash 复制代码
{ "_id" : "1001", "name" : "张三", "favoriteFruits" : [ "apple" ] }
{ "_id" : "1002", "name" : "李四", "favoriteFruits" : [ "banana" ] }
{ "_id" : "1003", "name" : "王五", "favoriteFruits" : [ "banana" ] }
{ "_id" : "1004", "name" : "赵六", "favoriteFruits" : [ ] }
{ "_id" : "1005", "name" : "田七", "favoriteFruits" : null }

如果position为负数,则从后往前确定起始位置,当向前移动的位置超过了数组长度,则起始位置为0;然后再从前往后获取N个元素组成新的数组。

数组表达式运算符过滤数组($filter)

数组表达式运算符主要用于文档中数组的操作,本篇我们主要介绍数组表达式运算符中用于过滤数组的操作,下面我们进行详细介绍:

一、语法

bash 复制代码
{
   $filter:
      {
         input: <array>,
         cond: <expression>,
         as: <string>,
         limit: <number expression>
      }
}

其中,

input:代表的是数组

cond:代表的是条件

as:可选,定义的变量,用于接收数组中的当前元素,如果未定义在cond表达式中可以使用$$this获取数组中的当前元素

limit:可选,限制数组中元素的个数

二、准备工作

初始化零食数据

bash 复制代码
db.goods.insertMany([
    { "_id" : 1, "name" : "薯片", "types" : [ 
        { "size" : "S", "quantity" : 10, "price" : 8 },
        { "size" : "L", "quantity" : 8, "price" : 12 } 
    ]},
    { "_id" : 2, "name" : "牛肉干", "types" : [ 
        { "size" : "L", "quantity" : 5, "price" : 30} 
    ]},
    { "_id" : 3, "name" : "可口可乐", "types" : [ 
        { "size" : "S", "quantity" : 10, "price" : 3 }, 
        { "size" : "L", "quantity" : 6, "price" : 10 } 
    ]},
    { "_id" : 4, "name" : "旺仔牛奶", "types" : [ 
        { "size" : "L", "quantity" : 10, "price" : 5 } 
    ]}
])

三、示例

例子1:只查看型号为L的型号信息

bash 复制代码
db.goods.aggregate([
    {
        $project: {
            types: {
                $filter: {
                    input: "$types",
                    cond: { $eq: [ "$$this.size", "L" ] }
                }
            }
        }
    }
])

等效于:

bash 复制代码
db.goods.aggregate([
    {
        $project: {
            types: {
                $filter: {
                    input: "$types",
                    as: "type",
                    cond: { $eq: [ "$$type.size", "L" ] }
                }
            }
        }
    }
])

聚合查询的结果如下:

bash 复制代码
{ "_id" : 1, "types" : [ { "size" : "L", "quantity" : 8, "price" : 12 } ] }
{ "_id" : 2, "types" : [ { "size" : "L", "quantity" : 5, "price" : 30 } ] }
{ "_id" : 3, "types" : [ { "size" : "L", "quantity" : 6, "price" : 10 } ] }
{ "_id" : 4, "types" : [ { "size" : "L", "quantity" : 10, "price" : 5 } ] }

as用于定义一个存储数组中当前元素的变量,使用变量时前面需要加上 "$$";

如果不使用as定义变量,也可以使用 $$this 访问数组中的当前元素

例子2:对超过5元的型号进行查询

bash 复制代码
db.goods.aggregate([
    {
        $project: {
            types: {
                $filter: {
                    input: "$types",
                    as: "type",
                    cond: { $gt: [ "$$type.price", 5 ] }
                }
            }
        }
    }
])

聚合查询的结果如下:

bash 复制代码
{ "_id" : 1, "types" : [ { "size" : "S", "quantity" : 10, "price" : 8 }, { "size" : "L", "quantity" : 8, "price" : 12 } ] }
{ "_id" : 2, "types" : [ { "size" : "L", "quantity" : 5, "price" : 30 } ] }
{ "_id" : 3, "types" : [ { "size" : "L", "quantity" : 6, "price" : 10 } ] }
{ "_id" : 4, "types" : [ ] }

多个查询条件

bash 复制代码
cond: {
  $and: [
    { $gte: ['$$item.timestamp_start', fromTimestamp] },
    { $lt: ['$$item.timestamp_start', toTimestamp] }
  ]
}

数组表达式运算符( a r r a y E l e m A t , arrayElemAt, arrayElemAt,first,$last)

数组表达式运算符主要用于文档中数组的操作,本篇我们主要介绍数组表达式运算符中用于获取数组元素的操作,下面我们进行详细介绍:

一、准备工作

初始化成员数据

plain 复制代码
db.persons.insertMany([
    { "_id" : "1001", "name" : "张三", "fruits" : [ "apple", "orange" ] },
    { "_id" : "1002", "name" : "李四", "fruits" : [ "banana", "apple" ] },
    { "_id" : "1003", "name" : "王五", "fruits" : [ "banana", "apple", "orange" ] },
    { "_id" : "1004", "name" : "赵六", "fruits" : [ ] },
    { "_id" : "1005", "name" : "田七" },
])

二、获取数组中指定元素($arrayElemAt)

语法:{ $arrayElemAt: [ , ] }

获取数组中指定索引位置的元素

:代表的是数组

:代表的是索引,索引为正数代表的是从前往后查找元素、为负数代表的是从后往前查找元素

数组的索引从0开始,最大值为数组的长度-1

例子1:找到每个人最喜欢吃的第一个水果

plain 复制代码
db.persons.aggregate([
    {
        $project: {
            "name": 1,
            "firstFruit": { $arrayElemAt: [ "$fruits", 0 ] }
        }
    }
])

聚合查询的结果如下:

plain 复制代码
{ "_id" : "1001", "name" : "张三", "firstFruit" : "apple" }
{ "_id" : "1002", "name" : "李四", "firstFruit" : "banana" }
{ "_id" : "1003", "name" : "王五", "firstFruit" : "banana" }
{ "_id" : "1004", "name" : "赵六" }
{ "_id" : "1005", "name" : "田七", "firstFruit" : null }

字段未定义时,结果为null,

索引超过数组边界则不返回结果。

例子2:找到每个人最喜欢吃的最后一个水果

plain 复制代码
db.persons.aggregate([
    {
        $project: {
            "name": 1,
            "lastFruit": { $arrayElemAt: [ "$fruits", -1 ] }
        }
    }
])

聚合查询的结果如下:

plain 复制代码
{ "_id" : "1001", "name" : "张三", "lastFruit" : "orange" }
{ "_id" : "1002", "name" : "李四", "lastFruit" : "apple" }
{ "_id" : "1003", "name" : "王五", "lastFruit" : "orange" }
{ "_id" : "1004", "name" : "赵六" }
{ "_id" : "1005", "name" : "田七", "lastFruit" : null }

索引为负数代表的是从后往前查找元素

三、获取数组中第一个元素($first)

语法:{ $first: }

获取数组中第一个元素

例子:找到每个人最喜欢吃的第一个水果

plain 复制代码
db.persons.aggregate([
    {
        $project: {
            "name": 1,
            "firstFruit": { $first: "$fruits" }
        }
    }
])

等效于:

plain 复制代码
db.persons.aggregate([
    {
        $project: {
            "name": 1,
            "firstFruit": { $arrayElemAt: [ "$fruits", 0 ] }
        }
    }
])

聚合查询的结果如下:

plain 复制代码
{ "_id" : "1001", "name" : "张三", "firstFruit" : "apple" }
{ "_id" : "1002", "name" : "李四", "firstFruit" : "banana" }
{ "_id" : "1003", "name" : "王五", "firstFruit" : "banana" }
{ "_id" : "1004", "name" : "赵六" }
{ "_id" : "1005", "name" : "田七", "firstFruit" : null }

四、获取数组中最后一个元素($last)

语法:{ $last: }

获取数组中最后一个元素

例子:找到每个人最喜欢吃的最后一个水果

plain 复制代码
db.persons.aggregate([
    {
        $project: {
            "name": 1,
            "lastFruit": { $last: "$fruits" }
        }
    }
])

等效于:

plain 复制代码
db.persons.aggregate([
    {
        $project: {
            "name": 1,
            "lastFruit": { $arrayElemAt: [ "$fruits", -1 ] }
        }
    }
])

聚合查询的结果如下:

plain 复制代码
{ "_id" : "1001", "name" : "张三", "lastFruit" : "orange" }
{ "_id" : "1002", "name" : "李四", "lastFruit" : "apple" }
{ "_id" : "1003", "name" : "王五", "lastFruit" : "orange" }
{ "_id" : "1004", "name" : "赵六" }
{ "_id" : "1005", "name" : "田七", "lastFruit" : null }
相关推荐
星星不说话0130 分钟前
Redis的Zset在排行榜中应用
数据库·redis·缓存
Elastic 中国社区官方博客1 小时前
Elasticsearch:管理和排除 Elasticsearch 内存故障
大数据·运维·数据库·elasticsearch·搜索引擎·全文检索
wh_xia_jun1 小时前
minio数据迁移
数据库
liuxin334455662 小时前
药典新篇:Spring Boot助力中药实验管理
数据库·spring boot·php
up向上up2 小时前
基于51单片机的电子钟+秒表LCD1602仿真设计
嵌入式硬件·mongodb·51单片机
WuMingf_2 小时前
Mongodb
数据库·mongodb
MrJson-架构师2 小时前
java 操作Mongodb
java·开发语言·mongodb
永乐春秋2 小时前
WEB攻防-通用漏洞&SQL注入&sqlmap&Oracle&Mongodb&DB2等
sql·mongodb·oracle
q567315233 小时前
Django 外键引用另一个表中的多个字段
开发语言·数据库·后端·django·sqlite