MongoDB系列--深入理解MongoDB聚合(Aggregation )

關注公衆號【Ccww筆記】,領取乾貨資料
  MongoDB中聚合(aggregate) 操作將來自多個document的value組合在一起,並通過對分組數據進行各種操作處理,並返回計算後的數據結果,主要用於處理數據(諸如統計平均值,求和等)。MongoDB提供三種方式去執行聚合操作:聚合管道(aggregation pipeline)Map-Reduce函數以及單一的聚合命令(count、distinct、group)

1. 聚合管道(aggregation pipeline)

1.1聚合管道

  聚合管道是由aggregation framework將文檔進入一個由多個階段(stage)組成的管道,可以對每個階段的管道進行分組、過濾等功能,然後經過一系列的處理,輸出相應的聚合結果。如圖所示:

聚合管道操作:

db.orders.aggregate([
      { $match: { status: "A" } },
      { $group: { _id: "$cust_id", total: { $sum: "$amount" } } }
])
  • $match階段:通過status字段過濾出符合條件的Document(即是Status等於“A”的Document);
  • $group 階段:按cust_id字段對Document進行分組,以計算每個唯一cust_id的金額總和。

1.2 管道

  管道在Unix和Linux中一般用於將當前命令的輸出結果作爲下一個命令的參數,MongoDB的聚合管道將MongoDB文檔在一個管道處理完畢後將結果傳遞給下一個管道處理。管道操作是可以重複的。
  最基本的管道功能提供過濾器filter,其操作類似於查詢和文檔轉換,可以修改輸出文檔的形式。
其他管道操作提供了按特定字段或字段對文檔進行分組和排序的工具,以及用於聚合數組內容(包括文檔數組)的工具。 此外,管道階段可以使用運算符執行任務,例如計算平均值或連接字符串。總結如下:

管道操作符

常用管道 解析
$group 將collection中的document分組,可用於統計結果
$match 過濾數據,只輸出符合結果的文檔
$project 修改輸入文檔的結構(例如重命名,增加、刪除字段,創建結算結果等)
$sort 將結果進行排序後輸出
$limit 限制管道輸出的結果個數
$skip 跳過制定數量的結果,並且返回剩下的結果
$unwind 將數組類型的字段進行拆分

表達式操作符

常用表達式 含義
$sum 計算總和,{$sum: 1}表示返回總和×1的值(即總和的數量),使用{$sum: '$制定字段'}也能直接獲取制定字段的值的總和
$avg 求平均值
$min 求min值
$max 求max值
$push 將結果文檔中插入值到一個數組中
$first 根據文檔的排序獲取第一個文檔數據
$last 同理,獲取最後一個數據

爲了便於理解,將常見的mongo的聚合操作和MySql的查詢做類比:

MongoDB聚合操作 MySql操作/函數
$match where
$group group by
$match having
$project select
$sort order by
$limit limit 
$sum sum()
$lookup join

1.3 Aggregation Pipeline 優化

  • 聚合管道可以確定它是否僅需要文檔中的字段的子集來獲得結果。 如果是這樣,管道將只使用那些必需的字段,減少通過管道的數據量
  • 管道序列優化化

管道序列優化化:
  1).使用$projector/$addFields+$match 序列優化:當Aggregation Pipeline中有多個$projectior/$addFields階段和$match 階段時,會先執行有依賴的$projector/$addFields階段,然後會新創建的$match階段執行,如下,

    { $addFields: {
    maxTime: { $max: "$times" },
    minTime: { $min: "$times" }
     } },
    { $project: {
    _id: 1, name: 1, times: 1, maxTime: 1, minTime: 1,
    avgTime: { $avg: ["$maxTime", "$minTime"] }
     } },
     { $match: {
    name: "Joe Schmoe",
    maxTime: { $lt: 20 },
    minTime: { $gt: 5 },
    avgTime: { $gt: 7 }
    } }

優化執行:

    { $match: { name: "Joe Schmoe" } },
      { $addFields: {
      maxTime: { $max: "$times" },
     minTime: { $min: "$times" }
    } },
    { $match: { maxTime: { $lt: 20 }, minTime: { $gt: 5 } } },
    { $project: {
       _id: 1, name: 1, times: 1, maxTime: 1, minTime: 1,
      avgTime: { $avg: ["$maxTime", "$minTime"] }
    } },
    { $match: { avgTime: { $gt: 7 } } }

  2). $sort + $match 以及$project + $skip,當$sort/$project跟在$match/$skip之後時,會先執行$match/$skip後再執行$sort/$project,$sort以達到最小化需排列的對象數,$skip約束,如下:

  { $sort: { age : -1 } },
  { $match: { score: 'A' } }
  { $project: { status: 1, name: 1 } },
  { $skip: 5 }

優化執行:


    { $match: { score: 'A' } },
    { $sort: { age : -1 } }
    { $skip: 5 },
    { $project: { status: 1, name: 1 } }

  3). $redact+$match序列優化,當$redact後有$match時,可能會新創一個$match階段進行優化,如下,

    { $redact: { $cond: { if: { $eq: [ "$level", 5 ] }, then: "$$PRUNE", else: "$$DESCEND" } } },
    { $match: { year: 2014, category: { $ne: "Z" } } }

優化執行:

    { $match: { year: 2014 } },
    { $redact: { $cond: { if: { $eq: [ "$level", 5 ] }, then: "$$PRUNE", else: "$$DESCEND" } } },
    { $match: { year: 2014, category: { $ne: "Z" } } }

還有很多管道序列優化可以查看《官方文檔-Aggregation Pipeline Optimization》。

1.4 Aggregation Pipeline以及分片(Sharded)collections

如果管道以$match精確分片 key開始的後,所有管道會在匹配的分片上進行。對於需運行在多分片中的聚合(aggregation)操作,如果不不需要在主分片進行的,這些操作後的結果會路由到隨機分片中進行合併結果,避免重載該主分片的數據庫。$out和$look階段必須在主分片數據庫運行。

2. Map-Reduce函數

  MongoDB還提供map-reduce操作來執行聚合。 通常,map-reduce操作有兩個階段一個map階段,它處理每個文檔併爲每個輸入文檔發出一個或多個對象,以及reduce階段組合map操作的輸出。 可選地,map-reduce可以具有最終化階段以對結果進行最終修改。 與其他聚合操作一樣,map-reduce可以指定查詢條件以選擇輸入文檔以及排序和限制結果。

  Map-reduce使用自定義JavaScript函數來執行映射和減少操作,以及可選的finalize操作。 雖然自定義JavaScript與聚合管道相比提供了極大的靈活性,但通常,map-reduce比聚合管道效率更低,更復雜。模式如下:

3. 單一的聚合命令

  MongoDB還提供了,db.collection.estimatedDocumentCount(),db.collection.count()和db.collection.distinct()
所有這些單一的聚合命令。 雖然這些操作提供了對常見聚合過程的簡單訪問操作,但它們缺乏聚合管道和map-reduce的靈活性和功能。模型如下

總結

  可使用MongoDB中聚合操作用於數據處理,可以適應於一些數據分析等,聚合的典型應用包括銷售數據的業務報表,比如將各地區的數據分組後計算銷售總和、財務報表等。最後想要更加深入理解還需要自己去實踐。

最後可關注公衆號,一起學習,每天會分享乾貨,還有學習視頻乾貨領取!

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