MongoDB入門實戰教程(6)
本系列教程目錄:
通過前面幾篇的學習,作為後端開發的我們基本可以應付70%的開發場景。接下來,我們就來看點進階一點的東西,首先是聚合查詢。
1 聚合框架簡介
前面的學習我們都是針對單個Collection操作的,雖然在MongoDB中針對Collection的設計就已經是無模式的,因此我們大部分場景都是針對單個Collection進行操作。
但是,我們在實際應用場景中還是會遇到想要SQL查詢中的 GROUP BY、LEFT OUTER JOIN、AS等操作。
好在,MongoDB提供了一套聚合框架(Aggregation Framework),它可以幫助我們在一個或多個Collection上,對Collection中的資料進行一系列的計算,並將這些資料轉化為期望的格式。
整個聚合計算的過程也被稱之為管道(Pipeline),由多個步驟(Stage)組成,這一點和Jenkins Pipeline比較類似。其中,每個管道需要:
(1)接受一系列Document(原始資料)
(2)每個步驟對這些Document進行一系列的運算
(3)結果Document輸出給下一個步驟
整個管道的過程如下圖所示:
聚合計算的基本格式如下所示:
pipeline = [$stage1, $stage2, ...$stageN]; db.<CollectionName>.aggregate( pipeline, { options } );
2 聚合操作例項
示例資料資料庫
這裡我們使用《MongoDB入門實戰教程(3)》中使用Mongo Tools進行恢復的Mock資料庫中的orders集合來進行應用。
在orders集合中,約有100000條記錄。
每個order文件的資料模型如下所示:
練習1:目前為止的訂單總銷量
假設我們需要針對orders集合進行一個操作,計算到目前為止的所有訂單的總銷售額:
db.orders.aggregate([ { $group: { _id: null, total: { $sum: "$total" } } } ]);
這裡我們使用到了一個常見的步驟(Stage):$group,它和SQL中的GROUP BY等價,用於對資料進行分組。這裡我們僅僅是做一個求和,不需要對誰進行分組。
然後,我們還用到了一個分組步驟中常用的運算子:$sum,它和SQL中的SUM等價,用於對指定列的資料進行求和。這裡我們需要對total欄位進行一個求和。
下圖是查詢結果:
練習2:某個日期區間的訂單金額彙總
假設我們需要查詢在2019年第一季度已完成訂單的訂單總金額和訂單總數。
說明:第一季度為1月1日~3月31日,訂單狀態為completed。
db.orders.aggregate([ // 步驟1:匹配條件 { $match: { status: "completed", orderDate: { $gte: ISODate("2019-01-01"), $lt: ISODate("2019-04-01") } } }, // 步驟二:聚合訂單總金額、總運費、總數量 { $group: { _id: null, total: { $sum: "$total" }, shippingFee: { $sum: "$shippingFee" }, count: { $sum: 1 } } }, { $project: { // 計算總金額 grandTotal: { $add: ["$total", "$shippingFee"] }, count: 1, _id: 0 } } ])
可以看到,這是一個較為複雜的查詢,我們可以將其分為三步:
第一步,使用$match進行匹配,這一點是做的SQL中的WHERE操作。
第二步,使用$group進行分組,目的是為了使用SUM運算子求和。
第三步,使用$project進行投影,目的是選擇需要的或排除不需要的欄位顯示。
下圖是查詢結果:
3 MQL vs SQL
分頁查詢對比
在SQL中常使用SKIP 和 LIMIT 進行分頁查詢,在MQL中也有等價操作:
-- SQL SELECT FIRST_NAME AS `名`, LAST_NAME AS `姓` FROM Users WHERE GENDER = '男' SKIP 100 LIMIT 20 -- MQL db.users.aggregate([ {$match: {gender: "男"}}, {$skip: 100}, {$limit: 20}, {$project: { '名': '$first_name', '姓': '$last_name' }} ]);
分組查詢對比
在SQL中常使用GROUP BY + HAVING 的分組高階查詢,在MQL中也有等價操作:
-- SQL SELECT DEPARTMENT, COUNT(NULL) AS EMP_QTY FROM Users WHERE GENDER = '女' GROUP BY DEPARTMENT HAVING COUNT(*) < 10 -- MQL db.users.aggregate([ {$match: {gender: '女'}}, {$group: { _id: '$DEPARTMENT’, emp_qty: {$sum: 1} }}, {$match: {emp_qty: {$lt: 10}}} ]);
unwind
在MQL中有一個特有的步驟unwind,它可以實現將文件中的某一個數組型別欄位拆分成多條,每條包含陣列中的一個值。
> db.students.findOne() { name:'張三', score:[ {subject:'語文',score:84}, {subject:'數學',score:90}, {subject:'外語',score:69} ] } > db.students.aggregate([{$unwind: '$score'}]) {name: '張三', score: {subject: '語文', score: 84}} {name: '張三', score: {subject: '數學', score: 90}} {name: '張三', score: {subject: '外語', score: 69}}
4 總結
本文簡單介紹了MongoDB的Aggregation Framework 以及 如何使用聚合框架進行聚合查詢。
下一篇,我們會學習MongoDB的模式設計中的一些設計模式。
參考資料
Microsoft Doc,使用ASP.NETCore和MongoDB建立WebAPI
唐建法,《MongoDB高手課》(極客時間)
郭遠威,《MongoDB實戰指南》(圖書)
△推薦訂閱學習
作者:周旭龍
出處:https://edisonchou.cnblogs.com
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。