MongoEngine - 聚合


术语“聚合”用于处理数据并返回计算结果的操作。对集合中的一个或多个文档字段求和、计数和平均值可以称为聚合函数。

MongoEngine提供了aggregate()函数,封装了PyMongo的聚合框架。聚合操作使用集合作为输入并返回一个或多个文档作为结果。

MongoDB 使用数据处理管道的概念。一条管道可以有多个阶段。基本阶段提供了类似查询的过滤和操作。其他提供了按一个或多个字段进行分组和/或排序的工具、字符串连接任务、数组聚合工具等。

MongoDB 管道创建中定义了以下阶段 -

姓名 描述
$项目 通过添加新字段或删除现有字段来重塑流中的每个文档。
$匹配 过滤文档流以仅允许匹配的文档未经修改地传递到下一阶段。$match 使用标准 MongoDB 查询。
$编辑 通过根据文档本身存储的信息限制每个文档的内容来重塑每个文档。
$限额 限制不加修改地传递到管道的文档
$跳过 跳过前 n 个文档,并将未修改的剩余文档传递到管道。
$组 按给定标识符表达式对输入文档进行分组,并将累加器表达式应用于每个组。输出文档仅包含标识符字段和累积字段。
$排序 按指定的排序键对文档流重新排序。
$出 将聚合管道的结果文档写入集合。

聚合表达式使用字段路径来访问输入文档中的字段。要指定字段路径,请使用在字段名称前面加上美元符号 $$$ 前缀的字符串。表达式可以使用一个或多个布尔运算符($and、$or、$not)和比较运算符($eq、$gt、$lt、$gte、$lte 和 $ne)。

以下算术表达式也用于聚合 -

$添加 添加数字以返回总和。接受任意数量的参数表达式
$减去 返回第一个值减去第二个值的结果
$乘 将数字相乘以返回乘积。接受任意数量的参数表达式
$除法 返回第一个数字除以第二个数字的结果。接受两个参数表达式
$mod 返回第一个数字除以第二个数字的余数。接受两个参数表达式

以下字符串表达式也可以用于聚合 -

$连接 连接任意数量的字符串
$子字符串 返回字符串的子字符串,从指定索引位置开始直到指定长度
降低$ 将字符串转换为小写。接受单个参数表达式
$到上层 将字符串转换为大写。接受单个参数表达式
$strcasecmp 执行字符串比较,如果两个字符串相等则返回 0,如果第一个字符串大于第二个字符串则返回 1,如果第一个字符串小于第二个字符串则返回 -1

为了演示aggregate()函数在MongoEngine中的工作原理,我们首先定义一个名为orders的Document类。

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

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

然后我们在订单集合中添加以下文档 -

_ID 客户ID 数量 地位
对象 ID("5eba52d975fa1e26d4ec01d0") A123 500 A
对象 ID("5eba536775fa1e26d4ec01d1") A123 250 A
对象 ID(“5eba53b575fa1e26d4ec01d2”) B212 200 D
对象 ID("5eba540e75fa1e26d4ec01d3") B212 400 A

仅当状态等于“A”时,aggregate() 函数才用于查找每个 custID 的金额字段总和。因此,管道构造如下。

管道的第一阶段使用 $match 来过滤 status='A' 的文档。第二阶段使用 $group 标识符对 CustID 上的文档进行分组并执行金额求和。

 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}