MongoDB查询实现 笛卡尔积,Union All 和Union 功能

转载自   MongoDB查询实现 笛卡尔积,Union All 和Union 功能

此篇文章及以后的文章大部分都是从聚合管道(aggregation pipeline)的一些语法为基础讲解的,如果不理解聚合管道的话,可以先学习一下会比较容易理解.
可以参考 mongoDB Documentation 的 Pipeline Aggregaion Stages.

何为Union All 和 Union

Union All指令的目的是将两个结果放在一起并且不管是否有重复,Union指令则把结果合并且去掉重复结果.


SQL中的实现Union All

在sql中,我们可以很简单的就实现 Union All 的效果.比如在sql中,我们的数据是

tableAidtypetableBidtype
 1OPEN 1OPEN
 2CLOSE 2ISSUE
 3REJECT 3VOID
 4REQUEST   

我们在sql中 Union All 的写法是:

select a.type as type from tableA a Union All select b.type from tableB b;

得到的结果是:

type
OPEN
CLOSE
REJECT
REQUEST
OPEN
ISSUE
VOID

MongoDB 的语法实现

在MongoDB中,对于给我们表联结相关使用的函数,有aggregate中的$lookup函数,
参照我们的官方例子,我们很容易就能理解$lookup函数的作用,相当于我们在sql里面的表联结,如:

select a.*,b.* from tableA a,tableB as b where a._id = b.tableAId;

$lookup函数中,有以下参数为必填:

  • from: <collection to join>, //等价于上面的 tableB

  • localField: <field from the input documents>,  //  等价于上面的 a._id

  • foreignField: <field from the documents of the "from" collection>, //等价于上面的 b.tableAId

  • as: <output array field> // 等价于上面as后面的 b

那么如何使用联结作用的函数来实现Union All 的作用呢?其实很简单,在上面的4个参数里面,localField 和 foreignField 是必填的,但是在mongo里面,我们可以填写一个无效的field(不存在表里面的field)来实现我们的效果

我们的测试数据如下:

tableA
{"_id":"1","type":"OPEN"}
{"_id":"2","type":"CLOSE"}
{"_id":"3","type":"REJECT"}
{"_id":"4","type":"REQUECT"}
tableB
{"_id":"1","type":"OPEN"}
{"_id":"2","type":"ISSUE"}
{"_id":"3","type":"VOID"}

1. 实现笛卡尔积

首先我们写的查询语句如下,将localField 和 foreignField随便填写一个String语句,只要是不在表里面存在的field即可

db.tableA.aggregate([{$lookup:{from:"tableB",localField:"invalidField",foreignField:"testField",as:"tableB"}}
])

查询结果:

_idtypetableB
1OPEN[3 elements]
1CLOSE[3 elements]
1REJECT[3 elements]
1REQUEST[3 elements]

在MongoDB里面,field的判断是空等于空的,value的判断空是不等于空的. 两个等于空的field去比较,相当于 在sql 里面 where 1=1 的写法.

可以看到,我们tableA的每一条记录都匹配到了tableB的3个元素(所有数据),此时只要我们将tableB的记录 $unwind出来,就实现了笛卡尔积的效果了.

$unwind语法如下:

db.tableA.aggregate([{$lookup:{from:"tableB",localField:"invalidField",foreignField:"testField",as:"tableB"}},{$unwind:{path:"$tableB"}},{$project:{_id:1,type:1,tableBId:"$tableB._id",tableBType:"$tableB.type"}}
])

等价于sql语句:

select a.id,a.type,b.id as tableId,b.type as tableBType from tableA a,tableB bwhere 1=1;

查询结果可以自行测试


2. 实现Union

在MongoDB里面,有一个$setUnion的函数,$setUnion函数被union的参数必需是数组,
在我们tableA lookup tableB之后返回来的结果,tableB已经是一个一个数组了,但是我们的tableA的type是一个字符串值,所以我们需要先将tableA的内容先转为数组,才能进行union.

All operands of $setUnion must be arrays.

将tableA里面的所有记录转为一个数组需要用到$gourp函数里面的$push功能.
查询语法如下:

db.tableA.aggregate([{$group:{_id:"any",tableA:{$push: "$$ROOT"}}}
])

查询结果:

_idtableA
any[4 elements]

因为$gourp函数里面的_id属性是必选的,但是这里我们不用到,所以填任意字符串或者null都可以.使用$push之后,tableA的所有记录,都被push到了我们命名为tableA的数组里面,
此时我们在$lookup tableB看看结果如何.
查询语法如下:

db.tableA.aggregate([{$group:{_id:"any",typeArray:{$push: "$$ROOT"}}},{$lookup:{from:"tableB",localField:"invalidField",foreignField:"testField",as:"tableB"}} 
])

查询结果:

_idtableAtableB
any[4 elements][3 elements]

可以看到,我们的tableA,和tableB的结果都变成了数组,此时我们已经可以使用$setUnion函数去实现我们的Union效果了

db.tableA.aggregate([{$group:{_id:"any",tableA:{$push: "$$ROOT"}}},{$lookup:{from:"tableB",localField:"invalidField",foreignField:"testField",as:"tableB"}},{$project:{_id:0,allValue:{$setUnion:["$tableA","$tableB"]}}}
])

查询结果:

allValue
[6 elements]

此处只有6个元素在数组里面,已经把重复的去掉了,可以说我们的Union效果已经实现,之后在把结果用$unwind展开即可.
查询语法如下:

db.tableA.aggregate([{$group:{_id:"any",tableA:{$push: "$$ROOT"}}},{$lookup:{from:"tableB",localField:"invalidField",foreignField:"testField",as:"tableB"}},{$project:{_id:0,allValue:{$setUnion:["$tableA","$tableB"]}}},{$unwind:{path:"$allValue"}},{$project:{_id:0,type:"$allValue.type"}},])

3. 实现Union All

实现Union All 的原理与union 的类似,我们可以在把tableA push 成一个数组前,新增一个field,或者只push type,那么在union的时候,因为table A 和 table B field 数量不一致,那么永远不会合并成一行,因为它们任意一行都是不一样的.
查询语法如下:

db.tableA.aggregate([{$group:{_id:"any",tableA:{$push: {type:"$type"}}}},{$lookup:{from:"tableB",localField:"invalidField",foreignField:"testField",as:"tableB"}},{$project:{_id:0,allValue:{$setUnion:["$tableA","$tableB"]}}},{$unwind:"$allValue"},{$project:{_id:0,type:"$allValue.type"}}
])

Union All 的结果,可以通过group的方式去重来变成 Union 的效果. $group函数在此就不再细讲,可以参考官网.


总结

在我们的MongoDB官方文档里面介绍了一些函数的基本语法,但是功能方面比较Oracle等传统关系型数据库来说还是比较少的,因为一些如本文讲的Union等这些功能,只能根据现有的功能去实现.
而在官网和网上现有的资料里面,是没有实现Union这些功能的介绍的,因此写下了这篇文档.

 

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

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

相关文章

袜子商店应用:一个云原生参照应用

本文要点 袜子商店应用始于一个简单的演示应用&#xff0c;之后发现它十分有用&#xff0c;最终演化成一个完全容器化的、云原生参照应用。该应用混合使用了Go、Java、Spring以及Node.js。它拥有完整的持续集成和发布管道&#xff0c;最终会发布到AWS上Kubernetes集群的准生产…

《朝花夕拾》金句摘抄(二)

System.out.println("今天看到朝花夕拾"); System.out.println("很好的一部书"); System.out.println("看起来比较吃力&#xff0c;很难理解");但我家的所在很偏僻&#xff0c;待到赛会的行列经过时&#xff0c;一定已在下午&#xff0c;仪仗之类…

最值得程序员get的30本行业干货

转载自 最值得程序员get的30本行业干货 1、互联网人的焦虑 互联网人是最焦虑的那批人&#xff0c;也是最爱学习的那批人。没办法&#xff0c;互联网行业的节奏实在太快了&#xff0c;每天都生活在信息爆炸的环境里&#xff0c;“风口”一个接一个。 网约车还没追上&#x…

编写高性能 .NET 代码 第二章:垃圾回收

垃圾回收是你开发工作中要了解的最重要的事情。它是造成性能问题里最显著的原因&#xff0c;但只要你保持持续的关注&#xff08;代码审查&#xff0c;监控数据&#xff09;就可以很快修复这些问题。我这里说的“显著的原因”&#xff0c;实际上是我们对垃圾回收的理解和期望不…

java中判断一个字符在字符串中出现的次数

源代码&#xff1a; //java中判断一个字符出现的次数//在下面字符串中查找有几个啊public static void testFindChar(){String str "啊&#xff01;我爱你中国&#xff01;啊&#xff0c;我爱你故乡";//存放每个字符的数组String [] strs new String[str.length()…

frameset和frame

<!--<!DOCTYPE html> <html><head><meta charset"utf-8"><title>body的简单标签</title></head><frameset rows"100px,*,100px" border"1px"><frame src"http://www.baidu.com"…

深入浅出 Java 中的包装类

转载自 深入浅出 Java 中的包装类 前阵子&#xff0c;我们分享了《Java中的基本数据类型转换》这篇文章&#xff0c;对许多粉丝还是有带来帮助的&#xff0c;今天讲一下 Java 包装类的的由来&#xff0c;及自动装箱、拆箱的概念和原理。 什么是包装类型 Java 设计当初就提…

java中实现将一个数字字符串转换成逗号分隔的数字串, 即从右边开始每三个数字用逗号分隔

源代码如下&#xff1a; /*将一个数字字符串转换成逗号分隔的数字串&#xff0c;即从右边开始每三个数字用逗号分隔 */public static void testFenGeNumber(){String number "1235954";StringBuffer sb new StringBuffer(number);for(int i number.length()-3;i&g…

事件总线(Event Bus)知多少

1. 引言 事件总线这个概念对你来说可能很陌生&#xff0c;但提到观察者&#xff08;发布-订阅&#xff09;模式&#xff0c;你也许就很熟悉。事件总线是对发布-订阅模式的一种实现。它是一种集中式事件处理机制&#xff0c;允许不同的组件之间进行彼此通信而又不需要相互依赖&…

《朝花夕拾》金句摘抄(三)

System.out.println("今天看到朝花夕拾"); System.out.println("很好的一部书"); System.out.println("看起来比较吃力&#xff0c;很难理解");我觉得他的话又在针对我&#xff0c;无理倒也并非无理的。第一个问题是&#xff1a;收不收&#xff…

影响程序员生涯的三个错误观念,你千万不要犯

转载自 影响程序员生涯的三个错误观念&#xff0c;你千万不要犯 程序员在社会上&#xff0c;到底是怎样一个生活群体&#xff1f;是否能找到自己方向&#xff1f;其实&#xff0c;路一直都在那里&#xff0c;只是你看不到而已&#xff01; 当初的你&#xff0c;可能一直被一…

用 docker secrets 保存 appsettings.Production.json

这是我们使用阿里云容器服务基于 docker 容器部署 asp.net core 应用遇到的另一个问题 —— 如果将包含敏感信息的应用配置文件 appsettings.Production.json 传递给运行在容器中的 asp.net core 应用。 Docker 针对这样的应用场景已经提供了解决方案 —— Docker Secrets&…

人脸识别简要说明

近日&#xff0c;或许是毕业季来临&#xff0c;或许是研究人脸识别的同行增多。总之&#xff0c;通过博客找我的人可所谓“络绎不绝”。 这几年来&#xff0c;自己不断的抽些碎片时间&#xff0c;整理出来的人脸识别各个版本&#xff0c;于2017年9月26日发布的java的第一个版本…

37 个 MySQL 数据库小技巧,不看别后悔!

转载自 37 个 MySQL 数据库小技巧&#xff0c;不看别后悔&#xff01; 无论是运维、开发、测试&#xff0c;还是架构师&#xff0c;数据库技术是一个必备加薪神器&#xff0c;那么&#xff0c;一直说学习数据库、学MySQL&#xff0c;到底是要学习它的哪些东西呢&#xff1f;…

《朝花夕拾》金句摘抄(四)

System.out.println("今天看到朝花夕拾"); System.out.println("很好的一部书"); System.out.println("看起来比较吃力&#xff0c;很难理解");我还能希求什么呢&#xff1f;我的心只得沉重着。灯火渐渐地缩小了&#xff0c;在预告石油的已经不多…

读《代码不朽:编写可维护软件的10大要则》C# 版

这本书特别针对没有接受过计算机科学或软件工程专业学习的软件开发人员&#xff0c;这类人员除了熟悉所用语言语法和语义之外&#xff0c;很少接受其他专业培训&#xff0c;对软件工程中的一些概念理解欠缺。软件设计方面考虑较少。如果要成为一个专业的程序员&#xff0c;就需…