MongoDB 聚合管道的集合关联($lookup)及合并($unionWith)

news2025/1/4 19:22:23

目前为止,我们已经介绍了一部分聚合管道中的管道参数:

        $match:文档过滤

        $group:文档分组,并介绍了分组中的常用操作:$addToSet,$avg,$sum,$min,$max等。

        $addFields:添加字段,等效于$set

        $unset:移除字段

        $project:字段投影

        $sort:文档排序

        $skip:跳过N条文档

        $limit:获取N条文档

        $sample:随机抽取N条文档

        $unwind:分解文档

如果需要进一步了解可以参考:
MongoDB 聚合管道的文档筛选及分组统计https://blog.csdn.net/m1729339749/article/details/130034658MongoDB 聚合管道的字段投影https://blog.csdn.net/m1729339749/article/details/130055110MongoDB 聚合管道的文档操作https://blog.csdn.net/m1729339749/article/details/130066663本篇我们介绍聚合管道的集合关联及合并操作:

一、准备工作

初始化零食数据

db.snacks.insertMany([
    { "_id": 1,  name: "薯片" },
    { "_id": 2,  name: "牛肉干" },
    { "_id": 3,  name: "可口可乐" },
    { "_id": 4,  name: "旺仔牛奶" }
])

初始化零食型号及储量

db.snacksType.insertMany([
    { "_id": 1, size: "S", quantity: 10, price: 8, expirationTime: ISODate( "2023-08-08T00:00:00Z" ), "snacks_id": 1 },
    { "_id": 2,  size: "L", quantity: 8, price: 12, expirationTime: ISODate( "2023-08-08T00:00:00Z" ), "snacks_id": 1 },
    { "_id": 3,  size: "L", quantity: 5, price: 30, expirationTime: ISODate( "2023-10-10T00:00:00Z" ), "snacks_id": 2 },
    { "_id": 4,  size: "S", quantity: 10, price: 3, expirationTime: ISODate( "2025-01-06T00:00:00Z" ), "snacks_id": 3 },
    { "_id": 5,  size: "L", quantity: 6, price: 10, expirationTime: ISODate( "2025-01-06T00:00:00Z" ), "snacks_id": 3 },
    { "_id": 6,  size: "L", quantity: 10, price: 5, expirationTime: ISODate( "2023-08-10T00:00:00Z" ), "snacks_id": 4}
])

二、使用字段关联查询($lookup)

语法:

{
   $lookup:
     {
       from: <collection to join>,
       localField: <field from the input documents>,
       foreignField: <field from the documents of the "from" collection>,
       as: <output array field>
     }
}

from:指的是关联的集合

localField:指的是当前管道中的字段

foreignField:指的是关联的集合中的字段

as:输出的数组字段;此字段将作为当前管道中的字段,字段的值来源于关联的集合中。

例子:在零食文档中关联上零食对应的所有型号信息

db.snacks.aggregate([
    {
        $lookup: {
            from: "snacksType",
            localField: "_id",
            foreignField: "snacks_id",
            as: "types"
        }
    }
])

我们对上面的聚合查询语法进行解释:

使用snacks集合中的字段_id与snacksType集合中的字段snacks_id进行关联查询snacksType集合中的文档,并将查询的结果作为当前管道中types字段的值。

聚合查询的结果如下:

{
	"_id" : 1,
	"name" : "薯片",
	"types" : [
		{
			"_id" : 1,
			"size" : "S",
			"quantity" : 10,
			"price" : 8,
			"expirationTime" : ISODate("2023-08-08T00:00:00Z"),
			"snacks_id" : 1
		},
		{
			"_id" : 2,
			"size" : "L",
			"quantity" : 8,
			"price" : 12,
			"expirationTime" : ISODate("2023-08-08T00:00:00Z"),
			"snacks_id" : 1
		}
	]
}
{
	"_id" : 2,
	"name" : "牛肉干",
	"types" : [
		{
			"_id" : 3,
			"size" : "L",
			"quantity" : 5,
			"price" : 30,
			"expirationTime" : ISODate("2023-10-10T00:00:00Z"),
			"snacks_id" : 2
		}
	]
}
{
	"_id" : 3,
	"name" : "可口可乐",
	"types" : [
		{
			"_id" : 4,
			"size" : "S",
			"quantity" : 10,
			"price" : 3,
			"expirationTime" : ISODate("2025-01-06T00:00:00Z"),
			"snacks_id" : 3
		},
		{
			"_id" : 5,
			"size" : "L",
			"quantity" : 6,
			"price" : 10,
			"expirationTime" : ISODate("2025-01-06T00:00:00Z"),
			"snacks_id" : 3
		}
	]
}
{
	"_id" : 4,
	"name" : "旺仔牛奶",
	"types" : [
		{
			"_id" : 6,
			"size" : "L",
			"quantity" : 10,
			"price" : 5,
			"expirationTime" : ISODate("2023-08-10T00:00:00Z"),
			"snacks_id" : 4
		}
	]
}

可以看出每个零食文档中都增加了一个数组字段types,里面包含了零食对应的型号

三、使用管道关联查询($lookup)

语法:

{
   $lookup:
      {
         from: <joined collection>,
         let: { <var_1>: <expression>, …, <var_n>: <expression> },
         pipeline: [ <pipeline to run on joined collection> ],
         as: <output array field>
      }
}

from:值的是关联的集合

let:可选,定义变量,这些变量可以在参数pipeline中使用

pipeline:指的是运行在关联的集合上的管道

as:输出的数组字段;此字段将作为当前管道中的字段,字段的值来源于关联的集合执行管道操作后输出的文档。

例子:在零食文档中关联上零食对应的型号、价格、储量、总价值信息

第一步:我们使用管道查询型号集合中的型号、总价值信息

db.snacksType.aggregate([
    {
        $project: {
            "_id": 0,
            "size": 1,
            "totalValue": { $multiply: [ "$price", "$quantity" ] }
        }
    }
])

执行的结果如下:

{ "size" : "S", "totalValue" : 80 }
{ "size" : "L", "totalValue" : 96 }
{ "size" : "L", "totalValue" : 150 }
{ "size" : "S", "totalValue" : 30 }
{ "size" : "L", "totalValue" : 60 }
{ "size" : "L", "totalValue" : 50 }

 第二步:根据零食关联型号信息

db.snacks.aggregate([
    {
        $lookup: {
            from: "snacksType",
            let: { "snackId": "$_id" },
            pipeline: [
                { 
                    $match: { 
                        $expr: { 
                            $eq: [ "$snacks_id", "$$snackId" ] 
                        } 
                    } 
                },
                {
                    $project: {
                        "_id": 0,
                        "size": 1,
                        "totalValue": { $multiply: [ "$price", "$quantity" ] }
                    }
                }
            ],
            as: "types"
        }
    }
])

我们对上面的聚合查询语法进行解释:

定义了snackId变量用于存储零食的编号(_id);在集合snacksType对应的管道上使用字段snacks_id对文档进行过滤,然后再进行字段投影。

定义的变量在使用时需要使用 $$ + 变量名;如果使用变量时,需要使用$expr运算符(在$expr运算符内部使用变量)

执行的结果如下:

{
	"_id" : 1,
	"name" : "薯片",
	"types" : [
		{
			"size" : "S",
			"totalValue" : 80
		},
		{
			"size" : "L",
			"totalValue" : 96
		}
	]
}
{
	"_id" : 2,
	"name" : "牛肉干",
	"types" : [
		{
			"size" : "L",
			"totalValue" : 150
		}
	]
}
{
	"_id" : 3,
	"name" : "可口可乐",
	"types" : [
		{
			"size" : "S",
			"totalValue" : 30
		},
		{
			"size" : "L",
			"totalValue" : 60
		}
	]
}
{
	"_id" : 4,
	"name" : "旺仔牛奶",
	"types" : [
		{
			"size" : "L",
			"totalValue" : 50
		}
	]
}

四、合并集合管道

语法:{ $unionWith: { coll: "<collection>", pipeline: [ <stage1>, ... ] } }

合并两个集合的管道

<collection>代表的是集合或者视图

[ <stage1>, ... ] 代表的是对<collection>进行处理的多个阶段组成的管道

例子:合并零食与型号集合中的文档

db.snacks.aggregate([
    {
        $project: { "name": 1, "_id": 0 }
    },
    {
        $unionWith: {
            coll: "snacksType",
            pipeline: [
                 { 
                    $project: { "size": "1", "_id": 0 } 
                 } 
            ]
        }
    }
])

我们对聚合查询进行一下解释:

(1) 使用$project 对snacks集合中的文档进行投影,投影后只保留了name字段

(2) 使用$project 对snacksType集合中的文档进行投影,投影后只保留了size字段

(3) 使用$unionWith 对两个集合的管道进行合并

执行的结果如下:

{ "name" : "薯片" }
{ "name" : "牛肉干" }
{ "name" : "可口可乐" }
{ "name" : "旺仔牛奶" }
{ "size" : "S" }
{ "size" : "L" }
{ "size" : "L" }
{ "size" : "S" }
{ "size" : "L" }
{ "size" : "L" }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/432088.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python OCR识别验证码

1. 抓取网页验证码图像并保存 import lxml.html, urllib3# 使用urllib3抓取网页数据 http urllib3.PoolManager() html http.request(GET,site).data# 使用lxml解析网页数据 tree lxml.html.fromstring(html) # 解析HTML&#xff0c;补全不完整的格式 fixedhtml lxml.ht…

LeetCode:102. 二叉树的层序遍历

&#x1f34e;道阻且长&#xff0c;行则将至。&#x1f353; &#x1f33b;算法&#xff0c;不如说它是一种思考方式&#x1f340;算法专栏&#xff1a; &#x1f449;&#x1f3fb;123 可以参考&#x1f449;LeetCode&#xff1a;二叉树的前、中、后序遍历——如何创建一棵【二…

机器学习 特征工程

文章目录 一、数据预处理1. 缺失值处理1.1 删除1.2 统计值填充1.3 前后向值填充1.4 直接忽略1.5 模型预测 2. 异常值处理 二、特征提取1. 数值型特征提取1.1 标准化与缩放1.1.1标准化&#xff08;Standardization&#xff09;1.1.2 归一化&#xff08;Normalization&#xff09…

STM32F4_定时器精讲(TIM)

目录 1. 什么是定时器&#xff1f; 2. STM32定时器简介 2.1 高级控制定时器 TIM1和TIM8 2.1.1 TIM1和TIM8简介 2.1.2 时基单元 2.1.3 计数器模式 2.1.4 重复计数器 2.1.5 时钟选择 2.1.6 捕获/比较通道 2.1.7 输入捕获模式 2.1.8 其他功能 2.2 通用定时器 TIM2到TI…

算法----删点成林

题目 给出二叉树的根节点 root&#xff0c;树上每个节点都有一个不同的值。 如果节点值在 to_delete 中出现&#xff0c;我们就把该节点从树上删去&#xff0c;最后得到一个森林&#xff08;一些不相交的树构成的集合&#xff09;。 返回森林中的每棵树。你可以按任意顺序组…

2023年天梯赛模拟赛

//能力有限&#xff0c;只展示一百分代码。前八个题一般是原题&#xff0c;所以不展示题目。 L1-1 嫑废话上代码 #include<bits/stdc.h> using namespace std; int main(){cout<<"Talk is cheap. Show me the code.";return 0; } L1-2 九牛一毛 这是…

Leetcode每日一题——“移除元素”

各位CSDN的uu们你们好呀&#xff0c;小雅兰又来啦&#xff0c;今天&#xff0c;小雅兰的内容是移除元素&#xff0c;下面&#xff0c;让我们进入Leetcode的世界吧 说明: 为什么返回数值是整数&#xff0c;但输出的答案是数组呢? 请注意&#xff0c;输入数组是以「引用」方式…

ChatGPT | 使用new bing的简易教程

1. 教程参考&#xff1a; https://juejin.cn/post/7199557716998078522 2.在参考上述教程遇到的问题与解决 2.1 下载dev浏览器的网址打不开 egde dev下载地址&#xff08;上面网站上的&#xff09;我电脑打不开 换用下面的网址即可 https://www.microsoftedgeinsider.com/z…

在three.js中废置对象

基于three.js子如何废置对象(How to dispose of objects) 前言: 为了提高性能,并避免应用程序中的内存泄露,一个重要的方面是废置未使用的类库实体。 每当创建一个three.js中的实例时,都会分配一定数量的内存。然而,three.js会创建在渲染中所必需的特定对象, 例如几何…

4.11、socket地址

4.11、socket地址1.通用 socket 地址2.专用socket地址1.通用 socket 地址 socket 网络编程接口中表示 socket 地址的是结构体 sockaddr&#xff0c;其定义如下&#xff1a; // socket地址其实是一个结构体&#xff0c;封装端口号和IP等信息。后面的socket相关的api中需要使用…

【c语言】每日一题之汉诺塔类型

目录 前言题目说明描述 题目分析汉诺塔问题 题目代码展示 前言 大佬们&#xff0c;我又回来了&#xff0c;最近也在忙自己的学业&#xff0c;忙着生活对线&#xff0c;也参加了今年的蓝桥杯其他的组&#xff0c;发现今年太难了 &#xff0c;摆烂了。但我想到了读者你们&#x…

前端面试之JavaScript题目,简单全面(持续更新ing...)

数据类型 1.JavaScript有哪些数据类型&#xff0c;它们的区别&#xff1f; 类型&#xff1a;JavaScript共有8种数据类型&#xff0c;undefined&#xff0c;null&#xff0c;Boolean&#xff0c;string&#xff0c;number&#xff0c;bigint&#xff0c;symbol&#xff0c;obj…

K-计算面积

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 小w给你三种图形&#xff0c;可能是平行四边形&#xff0c;三角形&#xff0c;梯形&#xff0c;对于给定的TTT个图形&#xff0c;你需要依次回答每个图形的面积&#xff0c;保证答案…

《LeetCode》——LeetCode刷题日记

本期&#xff0c;将给大家带来的是关于 LeetCode 的关于二叉树的题目讲解。 目录 &#xff08;一&#xff09;606. 根据二叉树创建字符串 &#x1f4a5;题意分析 &#x1f4a5;解题思路 &#xff08;二&#xff09;102. 二叉树的层序遍历 &#x1f4a5;题意分析 &#…

docker stats 命令详解

docker stats : 显示容器资源的使用情况&#xff0c;包括&#xff1a;CPU、内存、网络 I/O 等。 docker stats [OPTIONS] [CONTAINER...]OPTIONS 说明&#xff1a; –all , -a :显示所有的容器&#xff0c;包括未运行的。 –format :指定返回值的模板文件。 –no-stream :展…

( “树” 之 BFS) 637. 二叉树的层平均值 ——【Leetcode每日一题】

637. 二叉树的层平均值 给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 1 0 − 5 10^{-5} 10−5 以内的答案可以被接受。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[3.00000,14.50000,1…

060202体积弧长-定积分在几何学上的应用-定积分的应用

文章目录 2 体积2.1 旋转体的体积2.2 平行截截面面积已知的立体的体积2.3 例题 3 平面曲线的弧长2.1 直接坐标系2.2 参数方程2.3 极坐标系 结语 2 体积 2.1 旋转体的体积 情形①平面图形由 y f ( x ) , y 0 , x a , x b yf(x),y0,xa,xb yf(x),y0,xa,xb所围成&#xff0c;…

LeetCode——1041. 困于环中的机器人

一、题目 在无限的平面上&#xff0c;机器人最初位于 (0, 0) 处&#xff0c;面朝北方。注意: 北方向是y轴的正方向。 南方向是y轴的负方向。 东方向是x轴的正方向。 西方向是x轴的负方向。 机器人可以接受下列三条指令之一&#xff1a; “G”&#xff1a;直走 1 个单位 “L”…

seata1.5.2+nacos2.10配置教程

seata1.5.2配置教程本文基于nacos2.1.0mysql8.0seata1.5.21.下载安装包 官网&#xff1a;http://seata.io/zh-cn/blog/download.html seata目录结构如图&#xff1a; 2.主要需要修改的配置文件是\seata\conf\application.yml,可参考示例application.example.yml server:port:…

SpringBoot项目集成JMH测试用例

SpringBoot项目集成JMH测试用例1. JMH2. JMH使用2.1 pom引用JMH2.2 BaseBenchmark3. 部分注解介绍4. Jenkins 集成 JMH4.1 下载插件配置Job1. JMH JMH&#xff08;Java Microbenchmark Harness&#xff09;是一个 Java 工具&#xff0c;用于构建、运行和分析用 Java 和其他针对…