MongoDB 透過 lookup pipeline 實踐 Left Join

很久以前寫過一篇基本的 mongodb group 語法的基本介紹,在這些年間也持續跟 mongodb 持續纏鬥無法自拔…,對他又愛又恨,雖然超想拔掉他,但是從用途/功能性上卻無法找到他的取代品。

如今已經面臨要開始用他來 JOIN 了,感覺這毒是越吸越重了..XD 讓我們繼續看下去..

我們今天試著從 3.2 開始 aggregate 新支援的語法 $lookup 搭配 3.6 開始的 lookup pipeline 來解決我們需要 LEFT JOIN 的問題。

先複習一下,所有 mysql 跟 mongodb syntax 的 mapping,官方已經有一個不錯的文件快速幫助參照要怎麼把 SQL 轉換成 mongodb query

先來一個範例資料吧,現在有兩個 collection 使用者 user 跟訂單 order

如果用 SQL 的語法,要取得使用者的每筆訂單會這樣查詢

如果使用 mongodb 的 aggregate framework 的話則是透過從 3.2 開始支援的  lookup 

對應到 SQL 來看就蠻容易理解的,只是查詢出來的結構會是有多一個 orders 的 array 出現,不像是 SQL 被拆解成數筆資料,如果想要得到跟 SQL 一樣的結果也是可以透過 $unwind 來達成

這樣連帶造成的問題是 JOIN 起來的資料量有可能會因為 order 的數量不斷增加而變多,超過 BSON 單筆 16MB 的限制,資料就會查不出來了,會噴出如下錯誤

這個時候 3.6 開始支援的 $lookup pipeline 就可以解決這個問題了,就像在 SQL 中,你可以透過 JOIN 的 on 多增加一些條件,來減少需要被 JOIN 的資料量,pipeline 就是讓你在 lookup 重新獲得 aggregate 的能力

例如想要取得每一個使用者最新一筆訂單,可以改成

透過 pipeline 的 $match 來作為 on 的條件,搭配 pipeline 的 aggregate 能力,可以在做任何 $sort, $group 等語法,來讓最後 JOIN 進 document 的內容選擇只要你需要用到的資料

結論

就如同 SQL 有子查詢的能力一般,在這個版本上,幾乎可以滿足 90% 以上 SQL 的查詢能力了,Pipeline 的彈性甚至超越 SQL( Declarative programming),因為更偏向指令、流程(Imperative programming) 的描述方式一些, 只是這種混種品寫起來會很想死而已XD

之前有試用過 Mongodb 的 bi-connector,他就是幫你把 SQL 轉成 mongodb 的 aggregate,解決這種痛苦的窘境,但是當初試用的時候還在 3.2 的版本的關係,其隨便一句 SQL 就能跑到要崩潰都還出不來,也不見得有辦法建立索引改進。

如今看來 Mongodb 為了朝向大眾市場,看得出來很努力在新的版本解決這些問題,說不定有一天 Mongodb 預設裝起來就能透過 SQL 來 Query 也說不定呢,就像 BigQuery 一樣,因為原本語法不是標準 SQL,所以改進起來也沒有包袱,一個版本一個版本都可以有革命性的變革,只是看起來很像是數十年前 SQL 剛被標準化時的發展軌跡呀

參考資料

官方的 lookup 說明文件,有更多範例喔 https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *