MongoEngine - 聚合



術語“聚合”用於處理資料並返回計算結果的操作。在集合中一個或多個文件欄位上查詢總和、計數和平均值可以稱為聚合函式。

MongoEngine 提供了aggregate()函式,該函式封裝了 PyMongo 的聚合框架。聚合操作使用集合作為輸入,並返回一個或多個文件作為結果。

MongoDB 使用資料處理管道這一概念。一個管道可以有多個階段。基本階段提供過濾器和類似查詢的操作。其他階段提供用於根據一個或多個欄位進行分組和/或排序、字串連線任務、陣列聚合工具等的工具。

以下是在 MongoDB 管道建立中定義的階段:

名稱 描述
$project 透過新增新欄位或刪除現有欄位來重塑流中的每個文件。
$match 過濾文件流,只允許匹配的文件以未修改的方式傳遞到下一階段。$match 使用標準的 MongoDB 查詢。
$redact 透過根據文件本身儲存的資訊限制每個文件的內容來重塑每個文件。
$limit 限制要以未修改的方式傳遞到管道的文件
$skip 跳過前 n 個文件,並將剩餘的文件以未修改的方式傳遞到管道。
$group 根據給定的識別符號表示式對輸入文件進行分組,並將累加器表示式應用於每個組。輸出文件僅包含識別符號欄位和累加欄位。
$sort 根據指定的排序鍵重新排序文件流。
$out 將聚合管道的結果文件寫入集合。

聚合表示式使用欄位路徑來訪問輸入文件中的欄位。要指定欄位路徑,請使用以美元符號$作為字首的欄位名稱的字串。表示式可以使用一個或多個布林運算子($and、$or、$not)和比較運算子($eq、$gt、$lt、$gte、$lte 和 $ne)。

以下算術表示式也用於聚合:

$add 將數字相加以返回總和。接受任意數量的引數表示式
$subtract 返回從第一個值減去第二個值的結果
$multiply 將數字相乘以返回乘積。接受任意數量的引數表示式
$divide 返回第一個數字除以第二個數字的結果。接受兩個引數表示式
$mod 返回第一個數字除以第二個數字的餘數。接受兩個引數表示式

以下字串表示式也可以用於聚合:

$concat 連線任意數量的字串
$substr 返回字串的子字串,從指定的索引位置開始到指定的長度
$toLower 將字串轉換為小寫。接受一個引數表示式
$toUpper 將字串轉換為大寫。接受一個引數表示式
$strcasecmp 執行字串比較,如果兩個字串等效則返回 0,如果第一個大於第二個則返回 1,如果第一個字串小於第二個則返回 -1

為了演示aggregate()函式在 MongoEngine 中的工作原理,讓我們首先定義一個名為 orders 的文件類。

from mongoengine import *
con=connect('mydata')

class orders(Document):
   custID = StringField()
   amount= IntField()
   status = StringField()

然後我們在 orders 集合中新增以下文件:

_id custID amount status
ObjectId("5eba52d975fa1e26d4ec01d0") A123 500 A
ObjectId("5eba536775fa1e26d4ec01d1") A123 250 A
ObjectId("5eba53b575fa1e26d4ec01d2") B212 200 D
ObjectId("5eba540e75fa1e26d4ec01d3") B212 400 A

aggregate() 函式用於查詢僅當 status 等於“A”時每個 custID 的 amount 欄位的總和。因此,管道構建如下。

管道中的第一階段使用 $match 過濾 status='A' 的文件。第二階段使用 $group 識別符號根據 CustID 對文件進行分組,並執行 amount 的總和。

 pipeline = [
{"$match" : {"status" : "A"}},
{"$group": {"_id": "$custID", "total": {"$sum": "$amount"}}}
]

此管道現在用作 aggregate() 函式的引數。

docs = orders.objects().aggregate(pipeline)

我們可以使用 for 迴圈迭代文件遊標。完整的程式碼如下:

from mongoengine import *
con=connect('mydata')

class orders(Document):
   custID = StringField()
   amount= IntField()
   status = StringField()

pipeline = [
   {"$match" : {"status" : "A"}},
   {"$group": {"_id": "$custID", "total": {"$sum": "$amount"}}}
   ]
docs = orders.objects().aggregate(pipeline)
for doc in docs:
   print (x)

對於給定的資料,生成以下輸出:

{'_id': 'B212', 'total': 400}
{'_id': 'A123', 'total': 750}
廣告

© . All rights reserved.