MongoDB - 聚合查詢

来源:https://www.cnblogs.com/fatedeity/archive/2022/11/24/16920756.html
-Advertisement-
Play Games

在實際使用時,必不可少地需要將多個文檔甚至是多個集合彙總到一起計算、分析,MongoDB 提供了原生聚合框架支持這樣的計算、分析。 ...


聚合管道

聚合框架是 MongoDB 中的一組分析工具,可以對一個或多個集合中的文檔進行分析。

MongoDB 的聚合框架基於管道的概念:首先從集合中獲取到輸入,然後將輸入的文檔傳遞到一個或多個階段,每個階段都將之前階段輸出的內容作為輸入,最終得到一個聚合結果作為輸出。

聚合管道

上面的圖是一個比較寬泛的管道流程圖。這裡展示一個 MongoDB 聚合語句映射到管道之後的情況:

聚合流程圖示

在這裡可以看得出,aggregate([{}, {}]) 是一個聚合語句,在函數的數組中,每一個對象都是一個階段,$match 應該就是一個篩選文檔的階段,$group 應該就是一個分組彙總的階段。

管道階段

使用聚合框架最重要的就是熟悉操作的語法,以及將這些語法構建成管道當中的階段。

在 MongoDB 聚合框架中,每一個階段都必須要規定一個特定的階段運算符,這些階段運算符表明瞭階段的執行規則,可以到 官方文檔 上查看更多、更詳細的內容。

常見操作

最常見的操作應該是能與普通查詢語句對應上的操作,如查詢、投影、排序、跳過、限制等等。雖然這些在一個 find() 語句中就能實現。

最常使用的操作就是查詢,也可以說是篩選、過濾,在聚合框架中使用 $match 來表明這是一個篩選文檔的階段。如下是其使用語法:

{ $match: { <query> } }

第二個則是投影,這個階段可以修改輸入文檔的結構,通常是重命名、增加、刪除屬性,也可以通過表達式創建計算結果以及嵌套文檔。如下是其使用語法:

// <field>: <1 or true>
// <field>: <0 or false>
// <field>: <expression>
{ $project: { <specification(s)> } }

排序、跳過、限制都比較容易理解,實際上可以與 find() 結果的游標支持的函數做聯繫。如下是其使用語法:

// 排序
{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }
// 跳過
{ $skip: <positive 64-bit integer> }
// 限制
{ $limit: <positive 64-bit integer> }

上述 5 個階段是最常用的階段,在使用時需要註重它們的效率,一般會使用這樣的順序去構建管道:

  1. 通過篩選語句過濾指定集合,得到符合要求的文檔列表;
  2. 如果排序非常重要,這一個階段需要在過濾文檔之後;
  3. 如果需要做分頁功能,應該是先執行跳過的階段,然後再到限制的階段;
  4. 最後,執行投影階段(進入投影階段的文檔應該儘量少)。

更多操作 - 投影

投影階段一個比較大的作用就是,限制下一步的文檔欄位數量,也就是刪除屬性,如下是使用方式:

// 不返回 _id 欄位
{ $project: { _id: 0 } }
// 不返回指定的 field 欄位
{ $project: { <field>: 0 } }

刪除屬性是黑名單的功能,投影階段也支持白名單的功能,即返回列表內的欄位,如下是使用方式:

// 返回指定的 field 欄位
{ $project: { <field>: 1 } }

前兩個功能是比較好理解的,但投影階段所能做的遠不止如此,還有很多其他的功能(投影階段支持大部分條件組),這裡做個簡單舉例:

// 將 author 嵌套文檔下 last 屬性賦值給 lastName 屬性
{ $project: { lastName: "$author.last" } }
// 上述的功能里,對於嵌套文檔和內嵌數組返回的結果是不一樣的,數組會繼承下來

// 投影支持類似於三元運算的表達式
{ $project: { lastName: {
    $cond: {
        if: { $eq: [ "", "$author.last" ] },
        then: "$$REMOVE",
        else: "$author.last",
    }
} } }

更多操作 - 展開

在處理數組時,一個比較常見的操作是為數組中的每一個元素形成一個輸出文檔。

一個實際的例子就是,一件衣服在庫存中有 S、M、L 三個尺寸,而這三個尺寸會存儲在同一個數組欄位當中,當我們聚合時想要將這一條文檔展開成三個文檔,一個尺寸對應一個文檔。

// 原始文檔
{
    "clothesId": "123456",
    "sizeList": ["S", "M", "L"]
}

// 展開後的文檔
{
    "clothesId": "123456",
    "sizeList": "S"
}
{
    "clothesId": "123456",
    "sizeList": "M"
}
{
    "clothesId": "123456",
    "sizeList": "L"
}

聚合過程中,展開階段的語法是:

{ $unwind: <field path> }
// 上述衣服的例子中,可以用以下語句來展開
{ $unwind: "$sizeList" }

更多操作 - 分組

分組是聚合管道中舉足輕重的一個階段,這裡的分組可以看作是 SQL 的 GOURP BY 語句,其能為聚合功能帶來非常大的可能性。

分組階段使用了 $group 運算符,支持使用一個鍵或多個鍵將輸入的文檔進行分組,其語法如下:

{
    $group: {
        // 分組的標識
        _id: <expression>,
        <field1>: { <accumulator1> : <expression1> },
        ...
    }
 }

其中 _id 是必須的,可以簡單指定分組的鍵,也可以使用條件組做處理後生成自定義鍵。

可選的 <field> 是分組後需要展示的鍵,並且可以指定條件組來決定它們的值是什麼。

尤其是,MongoDB 提供了累加器可以實現複雜的功能,如求和、平均值、最大值、最小值等等。

這裡有個對集合求和的例子,也是最簡單的使用:

{
    $group: {
        // 對類型進行分組
        _id: "type",
        // 這裡是求和,一個文檔記作 1 個,即對同類型的文檔進行計數
        count: { $sum: 1 },
    }
 }

更多操作 - 入庫

顧名思義,入庫需要作為管道中最後的階段,將管道生成的文檔寫入集合中。

聚合框架提供了 $out$merge 兩個運算符標識入庫階段,其中 $merge 是在 4.2 版本中引入的。這兩個操作符的語法如下:

// 指定資料庫和集合,會直接覆蓋
{ $out: { db: "<output-db>", coll: "<output-collection>" } }

// 配置更加豐富
{ $merge: {
    // 指定資料庫和集合
    into: <collection> -or- { db: <db>, coll: <collection> },
    // 確定唯一標識與集合中做匹配
    on: <identifier field> -or- [ <identifier field1>, ...],  // Optional
    // 設定變數
    let: <variables>,                                         // Optional
    // 如果標識存在時處理文檔的方式
    whenMatched: <replace|keepExisting|merge|fail|pipeline>,  // Optional
    // 如果標識不存在時處理文檔的方式
    whenNotMatched: <insert|discard|fail>                     // Optional
} }

如果可以的話,建議使用 $merge 作為寫入集合的首選方式,其功能更多。

當然,其真正的優勢是,可以按照按需生成的物化視圖(materialized view),在管道運行的階段,輸出到集合的內容會進行增量更新。

條件組累加器

在一些階段操作中,MongoDB 支持使用累加器來增強聚合功能,這裡說的累加器泛指求和、平均值、最大值、最小值等功能的操作符。

算術運算

這裡的算術運算不是統稱的四則運算,指的是與數學相關的運算,如平均值、求和等。

$avg 累加器用於計算平均值,通過是直接指定一個鍵名即可,使用 { $avg: "$keyName" } 這樣的語法。

$sum 累加器用於計算指定鍵的和,也是直接指定一個鍵名即可,使用 { $sum: "$keyName" } 這樣的語法。

最值運算

累加器支持的最值包括這些:最小值、最大值、最大的 n 個值。

最小值和最大值的理解都比較容易,使用也比較容易。最小值使用了 { $min: "$keyName" } 這樣的語法,最大值使用了 { $max: "$keyName" } 這樣的語法。

最大的 n 個值是在 5.2 版本新增的累加器,其作用是通過指定輸入的鍵,得到這些鍵值中排序後最大的 n 個值,其語法如下:

{
    $maxN: {
        // 指定鍵名  input: "$score"
        input: <expression>,
        // 指定數量  n: 3
        n: <expression>
    }
}

數組提取

這裡的數組提取指的是提取數組中的某個元素,現在能支持到的就是提取出數組中的前 n 個元素、後 n 個元素。

在這裡可以使用 $first$firstN$last$lastN 這樣的運算符,它們的語法分別如下:

{ $first: <expression> }

{
    $firstN: {
        input: <expression>,
        n: <expression>
    }
}

{ $last: <expression> }

{
    $lastN: {
        input: <expression>,
        n: <expression>
    }
}

其他運算

除了上述的累加器,聚合框架還有非常多其他的累加器,這裡簡單列一下:

  • $accumulator: 返回自定義累加器函數的結果
  • $addToSet: 返回一個無重覆值的數組
  • $bottom: 返回指定排序規則後最後 1 個元素
  • $bottomN: 返回指定排序規則後最後 n 個元素
  • $count: 返迴文檔的計數
  • $mergeObjects: 返回合併多個對象之後的結果
  • $push: 返回一個可以有重覆值的數組
  • $stdDevPop: 返回輸入值的總體標準差
  • $stdDevSamp: 返回輸入值的樣本標準差

這些累加器都有各自的用法,使用得當可實現非常強大的數據分析功能,完整的內容可以到 官方文檔 上查看。

首發於「程式員翔仔」,點擊查看更多。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • CentOS7 配置本地yum源軟體倉庫 先連接虛擬光碟機,對應的光碟機iso文件 沒有的去下載對應鏡像 Download (centos.org) https://www.centos.org/download/ 進入虛擬機,把光碟掛載到 指定目錄 下 [root@localhost ~]# mkdi ...
  • 在使用 Linux 系統的過程中,我們經常需要查看系統、資源、網路、進程、用戶等方面的信息,查看這些信息的常用命令值得瞭解和熟悉。 ...
  • 痞子衡嵌入式半月刊: 第 67 期 這裡分享嵌入式領域有用有趣的項目/工具以及一些熱點新聞,農曆年分二十四節氣,希望在每個交節之日準時發佈一期。 本期刊是開源項目(GitHub: JayHeng/pzh-mcu-bi-weekly),歡迎提交 issue,投稿或推薦你知道的嵌入式那些事兒。 上期回顧 ...
  • Python基礎之MySQL資料庫 一、約束概述 1、為什麼要約束 ​ 為了防止資料庫中存在不符合語義規定的數據和防止錯誤信息的輸入、輸出造成無效的操作而提出的 ​ 為了保證數據的完整性,SQL規範以約束的方式對錶數據進行額外的條件限制,從以下四個方面考慮 實體完整性:例如一個表中不能存在兩條相同的 ...
  • 摘要:DWS的負載管理分為兩層,第一層為cn的全局併發控制,第二層為資源池級別的併發控制。 本文分享自華為雲社區《GaussDB(DWS) 併發管控&記憶體管控》,作者: fighttingman。 1背景 這裡將併發管控和記憶體管控寫在一起,是因為記憶體管控實際是通過限制語句的併發達到記憶體管控的目的的。 ...
  • Pandas靈活強大,是數據分析必備工具庫!但處理大型數據集時,需過渡到PySpark才可以發揮並行計算的優勢。本文總結了Pandas與PySpark的核心功能代碼段,掌握即可絲滑切換。 ...
  • 學習思路: 1.需求是什麼? 2.方案是什麼? 3.邏輯是什麼? 4.開發中的問題?怎麼解決? 整體流量概況: 1.累計用戶量 2.每日新增用戶量 3.每日的訪問人數、次數 4.每日的全部訪問人均次數、時長和深度 5.計算用戶平均會話數 6.計算當日訪問IP數 7.新老用戶訪問占比 8.每日新老用戶 ...
  • 在進行對接數據時,經常會遇到對接的是介面數據。 關於在對接介面類型的數據,數據返回的為json數組形式的數據,需要講數組先解析出來,主要是通過 jsonpath 表達式 。 jsonpath 表達式 : 1、JSONPath是xpath在json的應用2、JSONPath 是參照xpath表達式來解 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...