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 }
相关推荐
松涛和鸣2 小时前
72、IMX6ULL驱动实战:设备树(DTS/DTB)+ GPIO子系统+Platform总线
linux·服务器·arm开发·数据库·单片机
likangbinlxa3 小时前
【Oracle11g SQL详解】UPDATE 和 DELETE 操作的正确使用
数据库·sql
r i c k3 小时前
数据库系统学习笔记
数据库·笔记·学习
野犬寒鸦3 小时前
从零起步学习JVM || 第一章:类加载器与双亲委派机制模型详解
java·jvm·数据库·后端·学习
IvorySQL4 小时前
PostgreSQL 分区表的 ALTER TABLE 语句执行机制解析
数据库·postgresql·开源
·云扬·4 小时前
MySQL 8.0 Redo Log 归档与禁用实战指南
android·数据库·mysql
IT邦德4 小时前
Oracle 26ai DataGuard 搭建(RAC到单机)
数据库·oracle
惊讶的猫5 小时前
redis分片集群
数据库·redis·缓存·分片集群·海量数据存储·高并发写
不爱缺氧i5 小时前
完全卸载MariaDB
数据库·mariadb
纤纡.5 小时前
Linux中SQL 从基础到进阶:五大分类详解与表结构操作(ALTER/DROP)全攻略
linux·数据库·sql