MongoDB聚合:$graphLookup

$graphLookup聚合阶段在一个集合中执行递归搜索,可以使用选项来控制递归搜索的深度和条件。

$graphLookup搜索过程总结如下:

  1. 输入文档进入$graphLookup聚合阶段。
  2. $graphLookup的搜索目标是from参数指定的集合(搜索参数的完整列表见下文)。
  3. 对于每个输入文档,搜索都从startWith指定的值开始。
  4. graphLookup使用startWith的值匹配由from指定的集合和connectToField指定的字段的值。
  5. 对于每个匹配文档,$graphLookupconnectFromField的值来检查每个from参数指定的集合下的connectToField参数指定的字段的值,然后将匹配上的from集合的文档放到由as参数指定的数组中。
    然后该步骤继续递归直到没有匹配的文档或操作达到由maxDepth参数指定的递归深度。然后$graphLookup把数组字段添加到输入文档。在完成所有的文档搜索后返回结果。

语法

{$graphLookup: {from: <collection>,startWith: <expression>,connectFromField: <string>,connectToField: <string>,as: <string>,maxDepth: <number>,depthField: <string>,restrictSearchWithMatch: <document>}
}

参数字段解释:

字段描述
from$graphLookup操作搜索的目标集合,递归匹配connectFromFieldconnnectToField字段的值,from指定的集合必须与当前集合在同一个数据库,并且不可以是同一个集合
startWith可选,表达式,connectFromField字段进行递归搜索的起始值。startWith的值也可以是数组,其每个值都会被遍历处理
connectFromField指定一个字段名,其值用于递归搜索匹配。与集合中其他文档connectToField相对应,如果其值是数组,则会在遍历时单独处理每个元素
connectToField其他文档中的字段名称,用于匹配connectFromField参数指定的字段值
as添加到每个输出文档中的数组字段名称。包含在$graphLook阶段遍历的所有文档(注意,数组元素的顺序不保证)
maxDepth可选,正整数,指定最大的递归深度
depthField可选,要添加到搜索路径中每个遍历文档的字段名称。该字段的值是文档的递归深度,长整数。递归深度值从零开始,因此第一次查找对应的深度为零
restrictSearchWithMatch可选,文档类型。为递归搜索指定额外的条件,其语法与查询过滤语法相同。可以在过滤条件中使用所有的聚合表达式,如:{ lastName: { $ne: "$lastName" } },该表达式无法在该上下文中查找lastName值与输入文档的lastName值不同的文档,因为“$lastName”将充当字符串文本,而不是字段路径

使用

分片集合

从MongoDB 5.1开始,可以在from参数中指定分片集合,但不能在事务中使用分片集合。

最大递归深度

maxDepth字段设置为0相当于一个非递归的$graphLookup搜索阶段

内存

$graphLookup阶段有100M内存的限制,如果想突破这个限制,可以为聚合指定allowDiskUse: true,该设置也会影响到$graphLookup中使用的其他聚合阶段。

视图和集合

如果执行涉及多个视图的聚合,如使用$lookup$graphLookup,视图必须有相同的集合。

举例

单个集合

employees集合有下面的文档:

{ "_id" : 1, "name" : "Dev" }
{ "_id" : 2, "name" : "Eliot", "reportsTo" : "Dev" }
{ "_id" : 3, "name" : "Ron", "reportsTo" : "Eliot" }
{ "_id" : 4, "name" : "Andrew", "reportsTo" : "Eliot" }
{ "_id" : 5, "name" : "Asya", "reportsTo" : "Ron" }
{ "_id" : 6, "name" : "Dan", "reportsTo" : "Andrew" }

下面的$graphLookup递归匹配employees集合中reportsToname字段,返回每个人的报告层次结构:

db.employees.aggregate( [{$graphLookup: {from: "employees",startWith: "$reportsTo",connectFromField: "reportsTo",connectToField: "name",as: "reportingHierarchy"}}
] )

操作返回下面的结果:

{"_id" : 1,"name" : "Dev","reportingHierarchy" : [ ]
}
{"_id" : 2,"name" : "Eliot","reportsTo" : "Dev","reportingHierarchy" : [{ "_id" : 1, "name" : "Dev" }]
}
{"_id" : 3,"name" : "Ron","reportsTo" : "Eliot","reportingHierarchy" : [{ "_id" : 1, "name" : "Dev" },{ "_id" : 2, "name" : "Eliot", "reportsTo" : "Dev" }]
}
{"_id" : 4,"name" : "Andrew","reportsTo" : "Eliot","reportingHierarchy" : [{ "_id" : 1, "name" : "Dev" },{ "_id" : 2, "name" : "Eliot", "reportsTo" : "Dev" }]
}
{"_id" : 5,"name" : "Asya","reportsTo" : "Ron","reportingHierarchy" : [{ "_id" : 1, "name" : "Dev" },{ "_id" : 2, "name" : "Eliot", "reportsTo" : "Dev" },{ "_id" : 3, "name" : "Ron", "reportsTo" : "Eliot" }]
}
{"_id" : 6,"name" : "Dan","reportsTo" : "Andrew","reportingHierarchy" : [{ "_id" : 1, "name" : "Dev" },{ "_id" : 2, "name" : "Eliot", "reportsTo" : "Dev" },{ "_id" : 4, "name" : "Andrew", "reportsTo" : "Eliot" }]
}

下表显示了文件的遍历路径:

{ "_id" : 5, "name" : "Asya", "reportsTo" : "Ron" }:

起始值文档reportsTo的值
{ ... "reportsTo" : "Ron" }
深度0{ "_id" : 3, "name" : "Ron", "reportsTo" : "Eliot" }
深度1{ "_id" : 2, "name" : "Eliot", "reportsTo" : "Dev" }
深度2{ "_id" : 1, "name" : "Dev" }

输出结果生成的层次结构Asya -> Ron -> Eliot -> Dev

多个集合

$lookup类似,$graphLookup可以跨同一数据库的集合

例如,在同一数据库中分别创建两个集合:

  • airports集合有下列文档:
db.airports.insertMany( [{ "_id" : 0, "airport" : "JFK", "connects" : [ "BOS", "ORD" ] },{ "_id" : 1, "airport" : "BOS", "connects" : [ "JFK", "PWM" ] },{ "_id" : 2, "airport" : "ORD", "connects" : [ "JFK" ] },{ "_id" : 3, "airport" : "PWM", "connects" : [ "BOS", "LHR" ] },{ "_id" : 4, "airport" : "LHR", "connects" : [ "PWM" ] }
] )
  • travelers集合有以下文档:
db.travelers.insertMany( [{ "_id" : 1, "name" : "Dev", "nearestAirport" : "JFK" },{ "_id" : 2, "name" : "Eliot", "nearestAirport" : "JFK" },{ "_id" : 3, "name" : "Jeff", "nearestAirport" : "BOS" }
] )

对于travelers集合中的每个文档,下面的聚合操作会查找airports集合中nearestAirport的值,并递归匹配connects字段和airport字段。该操作指定的最大递归深度为2

db.travelers.aggregate( [{$graphLookup: {from: "airports",startWith: "$nearestAirport",connectFromField: "connects",connectToField: "airport",maxDepth: 2,depthField: "numConnections",as: "destinations"}}
] )

操作返回下面的结果:

{"_id" : 1,"name" : "Dev","nearestAirport" : "JFK","destinations" : [{ "_id" : 3,"airport" : "PWM","connects" : [ "BOS", "LHR" ],"numConnections" : NumberLong(2) },{ "_id" : 2,"airport" : "ORD","connects" : [ "JFK" ],"numConnections" : NumberLong(1) },{ "_id" : 1,"airport" : "BOS","connects" : [ "JFK", "PWM" ],"numConnections" : NumberLong(1) },{ "_id" : 0,"airport" : "JFK","connects" : [ "BOS", "ORD" ],"numConnections" : NumberLong(0) }]
}
{"_id" : 2,"name" : "Eliot","nearestAirport" : "JFK","destinations" : [{ "_id" : 3,"airport" : "PWM","connects" : [ "BOS", "LHR" ],"numConnections" : NumberLong(2) },{ "_id" : 2,"airport" : "ORD","connects" : [ "JFK" ],"numConnections" : NumberLong(1) },{ "_id" : 1,"airport" : "BOS","connects" : [ "JFK", "PWM" ],"numConnections" : NumberLong(1) },{ "_id" : 0,"airport" : "JFK","connects" : [ "BOS", "ORD" ],"numConnections" : NumberLong(0) } ]
}
{"_id" : 3,"name" : "Jeff","nearestAirport" : "BOS","destinations" : [{ "_id" : 2,"airport" : "ORD","connects" : [ "JFK" ],"numConnections" : NumberLong(2) },{ "_id" : 3,"airport" : "PWM","connects" : [ "BOS", "LHR" ],"numConnections" : NumberLong(1) },{ "_id" : 4,"airport" : "LHR","connects" : [ "PWM" ],"numConnections" : NumberLong(2) },{ "_id" : 0,"airport" : "JFK","connects" : [ "BOS", "ORD" ],"numConnections" : NumberLong(1) },{ "_id" : 1,"airport" : "BOS","connects" : [ "JFK", "PWM" ],"numConnections" : NumberLong(0) }]
}

下表显示了递归搜索遍历的路径,最大深度为2,开始的airportJFK

开始值travelers集合中nearestAirport的值
{ ... "nearestAirport" : "JFK" }
深度0{ "_id" : 0, "airport" : "JFK", "connects" : [ "BOS", "ORD" ] }
深度1{ "_id" : 1, "airport" : "BOS", "connects" : [ "JFK", "PWM" ] }, { "_id" : 2, "airport" : "ORD", "connects" : [ "JFK" ] }
深度2{ "_id" : 3, "airport" : "PWM", "connects" : [ "BOS", "LHR" ] }

查询条件

下面的示例使用了一个包含一组文档的集合,文档中包含人名及其朋友和爱好的数组。聚合操作会找到一个特定的人,并遍历她的社交网络,找到爱好为golf的人。

集合people包含了下列文档:

{"_id" : 1,"name" : "Tanya Jordan","friends" : [ "Shirley Soto", "Terry Hawkins", "Carole Hale" ],"hobbies" : [ "tennis", "unicycling", "golf" ]
}
{"_id" : 2,"name" : "Carole Hale","friends" : [ "Joseph Dennis", "Tanya Jordan", "Terry Hawkins" ],"hobbies" : [ "archery", "golf", "woodworking" ]
}
{"_id" : 3,"name" : "Terry Hawkins","friends" : [ "Tanya Jordan", "Carole Hale", "Angelo Ward" ],"hobbies" : [ "knitting", "frisbee" ]
}
{"_id" : 4,"name" : "Joseph Dennis","friends" : [ "Angelo Ward", "Carole Hale" ],"hobbies" : [ "tennis", "golf", "topiary" ]
}
{"_id" : 5,"name" : "Angelo Ward","friends" : [ "Terry Hawkins", "Shirley Soto", "Joseph Dennis" ],"hobbies" : [ "travel", "ceramics", "golf" ]
}
{"_id" : 6,"name" : "Shirley Soto","friends" : [ "Angelo Ward", "Tanya Jordan", "Carole Hale" ],"hobbies" : [ "frisbee", "set theory" ]}

下面的聚合操作使用了3个阶段:

  • $match匹配name字段包含字符串"Tanya Jordan"的文档,返回一个输出文档。

  • $graphLookup将输出文档的friends字段与集合中其他文档的name字段连接起来,以遍历Tanya Jordan的社交网络。此阶段使用restrictSearchWithMatch参数只查找爱好数组中包含golf的文档。返回一个输出文档。

  • $project 塑造输出文档。列出的connections who play golf的名字取自输入文档的golfers数组。

db.people.aggregate( [{ $match: { "name": "Tanya Jordan" } },{ $graphLookup: {from: "people",startWith: "$friends",connectFromField: "friends",connectToField: "name",as: "golfers",restrictSearchWithMatch: { "hobbies" : "golf" }}},{ $project: {"name": 1,"friends": 1,"connections who play golf": "$golfers.name"}}
] )

操作返回下面的文档:

{"_id" : 1,"name" : "Tanya Jordan","friends" : ["Shirley Soto","Terry Hawkins","Carole Hale"],"connections who play golf" : ["Joseph Dennis","Tanya Jordan","Angelo Ward","Carole Hale"]
}

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

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

相关文章

Hive的排序——order by 、sort by、distribute by 、cluster by

Hive中的排序通常涉及到order by 、sort by、distribute by 、cluster by 一、语法 selectcolumn1,column2, ... from table [where 条件] [group by column] [order by column] [cluster by column| [distribute by column] [sort by column] [limit [offset,] rows]; …

计算机服务器中了mkp勒索病毒如何解密,mkp勒索病毒解密流程

随着网络技术的不断发展与应用&#xff0c;越来越多的企业走向数字化办公模式&#xff0c;计算机极大地方便了企业的正常生产运营&#xff0c;但网络威胁的手段也不断增加。近期&#xff0c;云天数据恢复接到很多企业的求助&#xff0c;企业的计算机服务器遭到了mkp勒索病毒攻击…

Linux_进程间通信

管道 System V 共享内存 System V IPC 接口介绍 由于进程地址空间的存在&#xff0c;所以进程间有具有独立性&#xff0c;一个进程看不到另一个进程的数据。那么如果我们想让进程间通信&#xff0c;就必须先让它们先看到同一份资源。常见的进程间通信的方法有管道&#xff0c;…

前端学习的笔记第二篇

vscode如何快速生成代码 ! Tab 效果&#xff1a; 解析&#xff1a; <!DOCTYPE html>: 指定当前html版本5。 <html lang"en">: lang > language&#xff0c;en > english。指定当前页面内容是英文的。 <meta charset"UTF-8">:…

猫头虎分享:Win11系统家庭版组策略编辑器怎么打开? Windows11家庭版没有gpedit.msc如何解决?

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

滑动小短剧影视微信小程序源码/带支付收益等模式

仿抖音滑动小短剧影视微信小程序源码&#xff0c;带支付收益等模式、支持无限滑动&#xff1b;高性能滑动、预加载、视频预览&#xff0c;支持剧情介绍&#xff0c;集合壁纸另外仿抖音滑动效果&#xff1b;支持会员模式&#xff0c;支持用户单独购买等等多功能。 丰富的后台设…

深度学习基础之《深度学习介绍》

一、深度学习与机器学习的区别 1、特征提取方面 机器学习&#xff1a;人工特征提取 分类算法 深度学习&#xff1a;没有人工特征提取&#xff0c;直接将特征值传进去 &#xff08;1&#xff09;机器学习的特征工程步骤是要靠手工完成的&#xff0c;而且需要大量领域专业知识…

面试题 05.07. 配对交换

​​题目来源&#xff1a; leetcode题目&#xff0c;网址&#xff1a;面试题 05.07. 配对交换 - 力扣&#xff08;LeetCode&#xff09; 解题思路&#xff1a; 若将所给数左移一位&#xff0c;则奇数位与目标值的奇数位相同&#xff1b;若将所给数右移一位&#xff0c;则偶数位…

Golang中的fmt包:格式化输入输出的利器

Golang中的fmt包&#xff1a;格式化输入输出的利器 在软件开发的世界里&#xff0c;fmt包就像是一位忠实的伙伴&#xff0c;始终陪伴着开发人员。它简化了格式化输入输出的过程&#xff0c;让打印和扫描数据变得轻松自如。无论是向控制台输出简单的消息&#xff0c;还是处理复杂…

Rust入门:如何在windows + vscode中关闭程序codelldb.exe

在windows中用vscode单步调试rust程序的时候&#xff0c;发现无论是按下stop键&#xff0c;还是运行完程序&#xff0c;调试器codelldb.exe一直霸占着主程序不退出&#xff0c;如果此时对代码进行修改&#xff0c;后续就没法再编译调试了。 目前我也不知道要怎么处理这个事&am…

数据结构——6.3 图的遍历

6.3 图的遍历 一、概念 图的广度优先遍历 树的广度优先遍历&#xff08;层序遍历&#xff09;&#xff1a;不存在“回路”&#xff0c;搜索相邻的结点时&#xff0c;不可能搜到已经访问过的结点&#xff1a; 若树非空&#xff0c;则根节点入队 若队列非空&#xff0c;队头元素…

C语言——oj刷题——调整数组使奇数全部都位于偶数前面

题目&#xff1a; 输入一个整数数组&#xff0c;实现一个函数&#xff0c;来调整该数组中数字的顺序使得数组中所有的奇数位于数组的前半部分&#xff0c;所有偶数位于数组的后半部分。 一、实现方法&#xff1a; 当我们需要对一个整数数组进行调整&#xff0c;使得奇数位于数…

python系统学习Day1

section1 python introduction 文中tips只做拓展&#xff0c;可跳过。 PartOne introduction 首先要对于python这门语言有一个宏观的认识&#xff0c;包括特点和应用场景。 特点分析&#xff1a; 优势 提供了完善的基础代码库&#xff0c;许多功能不必从零编写简单优雅 劣势 运…

C语言第二十三弹---指针(七)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 指针 1、sizeof和strlen的对比 1.1、sizeof 1.2、strlen 1.3、sizeof 和 strlen的对比 2、数组和指针笔试题解析 2.1、⼀维数组 2.2、二维数组 总结 1、si…

mysql经典4张表问题

1.数据库表结构关联图 2.问题&#xff1a; 1、查询"01"课程比"02"课程成绩高的学生的信息及课程分数3.查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩4、查询名字中含有"风"字的学生信息5、查询课程名称为"数学"&…

使用 C++23 从零实现 RISC-V 模拟器(4):完善 log 支持并支持更多指令

&#x1f449;&#x1f3fb; 文章汇总「从零实现模拟器、操作系统、数据库、编译器…」&#xff1a;https://okaitserrj.feishu.cn/docx/R4tCdkEbsoFGnuxbho4cgW2Yntc 这一节内容解析了更多的指令&#xff0c;并且提供了更详细的 log 输出从而进一步的定位问题。 具体代码可以…

面试计算机网络框架八股文十问十答第四期

面试计算机网络框架八股文十问十答第四期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01;关注专栏后就能收到持续更新&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1&#xff09;当在浏览器中输入 …

单片机学习笔记---AT24C02数据存储

目录 AT24C02数据存储 准备工作 代码讲解 I2C.c 模拟起始位置的时序 模拟发送一个字节的时序 模拟接收应答的时序 模拟接收一个字节的时序 模拟发送应答的时序 模拟结束位置的时序 I2C.h AT24C02.c 字节写&#xff1a;在WORD ADDRESS&#xff08;字地址&#xff…

「Linux」软件安装

MySQL5.7在CentOS安装 安装 配置yum仓库 更新密钥&#xff1a;rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022安装MySQL yum库&#xff1a;rpm -Uvh http://repo.mysql.com//mysql57-community-release-el7-7.noarch.rpm使用yum安装MySQL&#xff1a;yum -y in…

WebSocket原理详解

目录 1.引言 1.1.使用HTTP不断轮询 1.2.长轮询 2.websocket 2.1.概述 2.2.websocket建立过程 2.3.抓包分析 2.4.websocket的消息格式 3.使用场景 4.总结 1.引言 平时我们打开网页&#xff0c;比如购物网站某宝。都是点一下列表商品&#xff0c;跳转一下网页就到了商品…