MongoDB入門實戰教程(6)

本系列教程目錄:

MongoDB入門實戰教程(1)

MongoDB入門實戰教程(2)

MongoDB入門實戰教程(3)

MongoDB入門實戰教程(4)

MongoDB入門實戰教程(5)

通過前面幾篇的學習,作爲後端開發的我們基本可以應付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.NET Core和MongoDB創建WebAPI

唐建法,《MongoDB高手課》(極客時間)

郭遠威,《MongoDB實戰指南》(圖書)

△推薦訂閱學習

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章