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中,我們的數據是
| ? | 1 | OPEN | ? | 1 | OPEN |
| ? | 2 | CLOSE | ? | 2 | ISSUE |
| ? | 3 | REJECT | ? | 3 | VOID |
| ? | 4 | REQUEST | ? | ? | ? |
我們在sql中 Union All 的寫法是:
select?a.type?as?type?from?tableA?a?Union?All?select?b.type?from?tableB?b;得到的結果是:
| OPEN |
| CLOSE |
| REJECT |
| REQUEST |
| OPEN |
| ISSUE |
| VOID |
MongoDB 的語法實現
在MongoDB中,對于給我們表聯結相關使用的函數,有aggregate中的$lookup函數,
參照我們的官方例子,我們很容易就能理解$lookup函數的作用,相當于我們在sql里面的表聯結,如:
在$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"}} ])查詢結果:
| 1 | OPEN | [3 elements] |
| 1 | CLOSE | [3 elements] |
| 1 | REJECT | [3 elements] |
| 1 | REQUEST | [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功能.
查詢語法如下:
查詢結果:
| any | [4 elements] |
因為$gourp函數里面的_id屬性是必選的,但是這里我們不用到,所以填任意字符串或者null都可以.使用$push之后,tableA的所有記錄,都被push到了我們命名為tableA的數組里面,
此時我們在$lookup?tableB看看結果如何.
查詢語法如下:
查詢結果:
| 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"]}}} ])查詢結果:
| [6 elements] |
此處只有6個元素在數組里面,已經把重復的去掉了,可以說我們的Union效果已經實現,之后在把結果用$unwind展開即可.
查詢語法如下:
3. 實現Union All
實現Union All 的原理與union 的類似,我們可以在把tableA push 成一個數組前,新增一個field,或者只push type,那么在union的時候,因為table A 和 table B field 數量不一致,那么永遠不會合并成一行,因為它們任意一行都是不一樣的.
查詢語法如下:
Union All 的結果,可以通過group的方式去重來變成 Union 的效果.?$group函數在此就不再細講,可以參考官網.
總結
在我們的MongoDB官方文檔里面介紹了一些函數的基本語法,但是功能方面比較Oracle等傳統關系型數據庫來說還是比較少的,因為一些如本文講的Union等這些功能,只能根據現有的功能去實現.
而在官網和網上現有的資料里面,是沒有實現Union這些功能的介紹的,因此寫下了這篇文檔.
?
總結
以上是生活随笔為你收集整理的MongoDB查询实现 笛卡尔积,Union All 和Union 功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华罗庚的数学成就
- 下一篇: AppleScript学习笔记(一)初识