10分鐘簡單學習net core整合jwt許可權認證,快速接入專案落地使用
為什麼需要聚合
一般查詢可以通過 find() 方法,但如果是比較複雜的查詢或者資料統計的話,find() 方法可能就無能為力,這時需要聚合(aggregate)。
聚合操作處理資料文件並返回計算結果。聚合操作將來自多個文件的值分組在一起,可以對分組的資料執行各種操作以返回單個結果。
MongoDB 提供了三種執行聚合的方法:
- 聚合管道
- map- reduce 函式
- 單一目的聚合方法
什麼是聚合管道(aggregation pipeline)
聚合管道可以對資料文件進行變換和組合。聚合管道是基於資料流概念,資料進入管道經過一個或多個 stage,每個 stage 對資料進行操作(篩選,投射,分組,排序,限制或跳過)後輸出最終結果。
聚合管道語法
db.collection.aggregate(pipeline, options)
- pipeline:陣列型別
注:聚合管道可以對分片集合進行操作
Pipeline 管道
db.collection.aggregate( [ { <stage> },... ] )
MongoDB 聚合管道由多個 stage 階段組成。每個 stage 階段在文件通過管道時轉換文件。管道階段可以在管道中出現多次。
聚合管道原理
db.collection.aggregate([]) 是聚合管道查詢使用的方法,引數是陣列,每個陣列元素就是一個stage,stage 中運用操作符對資料進行處理後再交由下一個stage,直到沒有下個stage,就輸出最終的結果,而資料的處理則是通過使用管道操作符。
什麼是管道操作符
mongoDB 有 4 類操作符用於文件的操作(操作符以 $ 開頭)
- 查詢操作符
- 更新操作符
- 管道操作符(聚合管道中的操作符)
- 查詢修飾符
在 aggregate 中每個 stage 可以使用的操作符叫做管道操作符
管道操作符分類
- 階段操作符(Stage Operators)
- 表示式操作符(Expression Operators)
- 累加器(Accumulators)
階段操作符
db.collection.aggregate( [ { 階段操作符:表述 }, { 階段操作符:表述 }, ... ] )
階段操作符 | 操作符名稱 | 說明 |
---|---|---|
$count | 統計操作符 | 用於統計文件的數量 |
$group | 分組操作符 | 用於對文件集合進行分組 |
$limit | 限制操作符 | 用於限制返回文件的數量 |
$match | 匹配操作符 | 用於對文件集合進行篩選 |
$out | 輸出操作符 | 將聚合管道的結果文件寫入集合。要使用 $out階段,它必須是管道中的最後一個階段。 |
$project | 投射操作符 | 用於重構每一個文件的欄位,可以提取欄位,重新命名欄位,甚至可以對原有欄位進行操作後新增欄位 |
$skip | 跳過操作符 | 用於跳過指定數量的文件 |
$sort | 排序操作符 | 用於根據一個或多個欄位對文件進行排序 |
$unwind | 拆分操作符 | 用於將陣列中的每一個值拆分為單獨的文件 |
$lookup | 連線操作符 | 用於連線同一個資料庫中另一個集合,並獲取指定的文件,類似於populate |
$addFields | 欄位操作符 | 用於給聚合管道的結果文件新增欄位 |
$match 語法
匹配操作符,用於對文件集合進行篩選
{ $match: { <query> } }
$project 語法
用於重構每一個文件的欄位,可以提取欄位,重新命名欄位,甚至可以對原有欄位進行操作後新增欄位
{ $project: { <specification(s)> } }
specification 的規則如下:
規則 | 描述 |
---|---|
<欄位名>: 1 or true | 選擇需要顯示什麼欄位 |
_id: 0 or false | 不顯示 _id (預設顯示) |
<欄位名>: 表示式 | 使用表示式,可以用於重新命名欄位,或對其值進行操作,或新增欄位 |
<欄位名>: 0 or false | 選擇需要不返回什麼欄位,注意:當使用這種用法時,就不要用上面的方法 |
$addFields 語法
在聚合管道結果新增一些欄位資訊或者修改欄位資訊
{ $addField: <document> }
$skip 語法
用於跳過指定數量的文件
{ $skip: <positive integer> }
$limit 語法
用於限制返回文件的數量
{ $limit: <positive integer> }
$count 語法
{ $count: <string> }
- string:是輸出欄位的名稱,該欄位的值為 count。string 必須是非空字串,不能以 $ 開頭,也不能包含 .點字元
$sort 語法
用於根據一個或多個欄位對文件進行排序
{ $sort: { <field1>: <sort order>,<field2>: <sort order> ... } }
- 1:升序
- -1:降序
$out 語法
{ $out: "<output-collection>" }
$unwind 語法
用於將陣列中的每一個值拆分為單獨的文件
{ $unwind: { path: <field path>, includeArrayIndex: <string>, preserveNullAndEmptyArrays:<boolean> } }
- path:字串型別,陣列欄位的欄位路徑,若要指定欄位路徑,需要在欄位名稱前加上 $ 符號並將其括在引號內
- includeArrayIndex:可選項,用於儲存元素的陣列索引的新欄位的名稱。名稱不能以 $ 符號開頭
- preserveNullAndEmptyArrays:
- 如果為 true,如果路徑為空、沒有陣列欄位或陣列為空,則 $unwind 輸出文件
- 如果為 false,如果路徑為空、沒有陣列欄位或陣列為空,則 $unwind 不輸出文件(預設)
$lookup 語法
用於連線同一個資料庫中另一個集合,並獲取指定的文件
{ $lookup: { from: <collection to join>, localField: <field from the input documents>, foreignField: <field from the documents of the "from" collection>, as: <output array field> }}
欄位 | 描述 |
---|---|
from | 需要關聯的集合名 |
localField | 本集合中需要查詢的欄位 |
foreignField | 另外一個集合中需要關聯的欄位 |
as | 輸出的欄位名 |
$group 語法
用於對文件集合進行分組
{ $group: { _id: <expression>, <field1>: { <accumulator1> : <expression1> }, ... } }
- _id:是必須的,用作分組的依據條件
表示式(Expression)
表示式可以包括欄位路徑和系統變數、文字、表示式物件和表示式操作符。表示式可以巢狀。
{ <field1>: <expression1>, ... }
-
欄位路徑表示式:$
-
"$<field>” 等價於 “$$CURRENT.<field>”,其中 CURRENT 是一個系統變數,在大多數階段預設為當前物件的根.
-
聚合表示式使用欄位路徑訪問輸入文件中的欄位。若要指定欄位路徑,請使用字首為$符號欄位名的字串,如果欄位在嵌入的文件中,則使用點語法。
-
系統變量表達式:$$系統變數
-
$$CURRENT 表示當前文件
-
$$ROOT 整個文件
-
-
字面量表達式:返回不需要解析的值。用於聚合管道可解釋為表示式的值
-
表示式物件
-
表示式操作符
表示式操作符
表示式操作符主要用於在管道中構建表示式時使用,使用類似於函式那樣需要引數,主要用於 $project 操作符中,用於構建表示式,使用方法一般如下:
{ <operator>: [ <argument1>, <argument2> ... ] }# 或{ <operator>: <argument> }
表示式操作符分類
- 布林值操作符(Boolean Operators)
- 集合操作符(Set Operators)
- 比較操作符(Comparison Operators)
- 數學操作符(Arithmetic Operators)
- 字串操作符(String Operators)
- 文字搜尋操作符(Text Search Operators)
- 陣列操作符(Array Operators)
- 變數操作符(Variable Operators)
- 字面量操作符(Literal Operators)
- 日期操作符(Date Operators)
- 條件操作符(Conditional Operators)
- 資料型別操作符(Data Type Operators)
累加器(Accumulators)
累加器操作符 | 說明 |
---|---|
$avg | 返回數值的平均值(忽略非數字值) |
$max | 返回每個組的最高表示式值 |
$min | 返回每個組的最低表示式值 |
$push | 返回每個組的表示式值組成的陣列 |
$sum | 返回數值的和(忽略了非數字值) |
$avg 語法
{ $avg: [ <expression1>, <expression2>... ] }
$max 語法
{ $max: <expression> }{ $max: [ <expression1>, <expression2>... ] }
$push 語法
{ $push: <expression> }
$sum 語法
{ $sum: <expression> }
聚合管道優化
聚合管道操作有一個優化階段,該階段試圖重塑管道以提高效能
管道序列優化
-
$project or $addFields) 和 $match 順序優化
-
$sort 和 $match 順序優化
-
$skip 和 $limit 順序優化
-
$project 和 ($skip or $limit) 順序優化
管道聯合優化
- $sort 和 $limit 聯合優化
當 $sort 緊鄰 $limit 時,優化器可以將 $limit 合併到 $sort 中。這允許 $sort 操作在進行過程中只維護頂部的 n 個結果,其中 n 是指定的限制,MongoDB 只需要在記憶體中儲存 n 個條目。
- $limit 和 $limit 聯合優化
當一個 $limit 緊接另一個 $limit 之後,這兩個階段可以合併為一個 $limit,其中 $limit 值是兩個初始 $limit 值中較小的一個。
- $skip 和 $skip 聯合優化
當一個 $skip 緊接著另一個 $skip 時,這兩個階段可以合併為單個 $skip,其中 $skip 量是兩個初始 $skip 量的總和。
- $match 和 $match 聯合優化
當一個 $match 緊跟在另一個 $match 之後時,這兩個階段可以合併為一個結合了條件和 $and 的單個 $match
-
$sort 和 $skip 和 $limit 聯合優化
-
$limit 和 $skip 和 $limit 和 $skip 聯合優化