聚合(Aggregation)
Overview
在本指南中,您可以了解如何在 Rust 驱动程序中执行聚合操作。
聚合操作根据您在管道中设置的规范处理 MongoDB collection中的数据。聚合管道由一个或多个阶段组成。 每个阶段都根据其表达式操作符执行操作。 驱动程序执行聚合管道后,会返回聚合结果。
本指南包括以下部分:
比较聚合和查找操作描述了聚合和查找操作之间的功能差异
MongoDB Server限制描述了服务器对聚合操作的内存使用限制
示例提供了不同使用案例的聚合示例
附加信息提供了本指南中提到的类型和方法的资源和 API 文档链接
类比
聚合操作的功能类似于带有装配线的汽车工厂。 装配线设有配备专用工具的工位来执行特定任务。 例如,在制造汽车时,装配线从制造车架开始。 然后,当车架移动通过装配线时,每个工位都会组装一个单独的零件。 最终产品即成品汽车。
装配线代表聚合管道,各个工位代表聚合阶段,专用工具代表表达式操作符,而成品则代表聚合结果。
比较聚合与查找操作
下表列出了使用查找操作可以执行的不同任务,同时列出了使用聚合操作可以实现的任务作为对比。聚合框架提供了扩展功能,允许您转换和操作数据。
查找操作 | 聚合操作 |
---|---|
Select certain documents to return Select which fields to return Sort the results Limit the results Count the results | Select certain documents to return Select which fields to return Sort the results Limit the results Count the results Rename fields Compute new fields Summarize data Connect and merge data sets |
服务器限制
执行聚合操作时,请考虑以下限制:
返回的文档不得违反 BSON 文档大小限制(16 兆字节)。
默认,管道阶段的内存限制为 100 MB。如果需要,您可以通过在 中设置 allow_disk_use 字段来超过此限制。
AggregateOptions
$graphLookup操作符有100 MB 的严格内存限制,并忽略
allow_disk_use
设置。
示例
本节中的示例使用以下样本文档。 每个文档代表书评网站上的一个用户个人资料,并包含有关他们的姓名、年龄、类型兴趣以及他们最后一次活跃在网站上的日期的信息:
{ "name": "Sonya Mehta", "age": 23, "genre_interests": ["fiction", "mystery", "memoir"], "last_active": { "$date": "2023-05-13T00:00:00.000Z" } }, { "name": "Selena Sun", "age": 45, "genre_interests": ["fiction", "literary", "theory"], "last_active": { "$date": "2023-05-25T00:00:00.000Z" } }, { "name": "Carter Johnson", "age": 56, "genre_interests": ["literary", "self help"], "last_active": { "$date": "2023-05-31T00:00:00.000Z" } }, { "name": "Rick Cortes", "age": 18, "genre_interests": ["sci-fi", "fantasy", "memoir"], "last_active": { "$date": "2023-07-01T00:00:00.000Z" } }, { "name": "Belinda James", "age": 76, "genre_interests": ["literary", "nonfiction"], "last_active": { "$date": "2023-06-11T00:00:00.000Z" } }, { "name": "Corey Saltz", "age": 29, "genre_interests": ["fiction", "sports", "memoir"], "last_active": { "$date": "2023-01-23T00:00:00.000Z" } }, { "name": "John Soo", "age": 16, "genre_interests": ["fiction", "sports"], "last_active": { "$date": "2023-01-03T00:00:00.000Z" } }, { "name": "Lisa Ray", "age": 39, "genre_interests": ["poetry", "art", "memoir"], "last_active": { "$date": "2023-05-30T00:00:00.000Z" } }, { "name": "Kiran Murray", "age": 20, "genre_interests": ["mystery", "fantasy", "memoir"], "last_active": { "$date": "2023-01-30T00:00:00.000Z" } }, { "name": "Beth Carson", "age": 31, "genre_interests": ["mystery", "nonfiction"], "last_active": { "$date": "2023-08-04T00:00:00.000Z" } }, { "name": "Thalia Dorn", "age": 21, "genre_interests": ["theory", "literary", "fiction"], "last_active": { "$date": "2023-08-19T00:00:00.000Z" } }, { "name": "Arthur Ray", "age": 66, "genre_interests": ["sci-fi", "fantasy", "fiction"], "last_active": { "$date": "2023-11-27T00:00:00.000Z" } }
按类型划分的年龄见解
以下示例计算对每种类型感兴趣的用户的平均年龄、最小年龄和最大年龄。
聚合管道包含以下阶段:
$unwind
阶段,用于将genre_interests
字段中的每个数组条目分隔成新文档。$group
阶段,用于按genre_interests
字段的值对文档进行分组。 此阶段使用$avg
、$min
和$max
操作符查找用户的平均年龄、最小年龄和最大年龄。
let age_pipeline = vec![ doc! { "$unwind": doc! { "path": "$genre_interests" } }, doc! { "$group": doc! { "_id": "$genre_interests", "avg_age": doc! { "$avg": "$age" }, "min_age": doc! { "$min": "$age" }, "max_age": doc! { "$max": "$age" } } } ]; let mut results = my_coll.aggregate(age_pipeline).await?; while let Some(result) = results.try_next().await? { println!("* {:?}", result); }
* { "_id": "memoir", "avg_age": 25.8, "min_age": 18, "max_age": 39 } * { "_id": "sci-fi", "avg_age": 42, "min_age": 18, "max_age": 66 } * { "_id": "fiction", "avg_age": 33.333333333333336, "min_age": 16, "max_age": 66 } * { "_id": "nonfiction", "avg_age": 53.5, "min_age": 31, "max_age": 76 } * { "_id": "self help", "avg_age": 56, "min_age": 56, "max_age": 56 } * { "_id": "poetry", "avg_age": 39, "min_age": 39, "max_age": 39 } * { "_id": "literary", "avg_age": 49.5, "min_age": 21, "max_age": 76 } * { "_id": "fantasy", "avg_age": 34.666666666666664, "min_age": 18, "max_age": 66 } * { "_id": "mystery", "avg_age": 24.666666666666668, "min_age": 20, "max_age": 31 } * { "_id": "theory", "avg_age": 33, "min_age": 21, "max_age": 45 } * { "_id": "art", "avg_age": 39, "min_age": 39, "max_age": 39 } * { "_id": "sports", "avg_age": 22.5, "min_age": 16, "max_age": 29 }
按时间组件分组
以下示例查找每个月的最后活跃用户数。
聚合管道包含以下阶段:
$project
阶段将last_active
字段中的月份作为数字提取到month_last_active
字段$group
阶段按month_last_active
字段对文档进行群组并计算每个月的文档数量$sort
阶段对月份设立升序排序
let last_active_pipeline = vec![ doc! { "$project": { "month_last_active" : doc! { "$month" : "$last_active" } } }, doc! { "$group": doc! { "_id" : doc! {"month_last_active": "$month_last_active"} , "number" : doc! { "$sum" : 1 } } }, doc! { "$sort": { "_id.month_last_active" : 1 } } ]; let mut results = my_coll.aggregate(last_active_pipeline).await?; while let Some(result) = results.try_next().await? { println!("* {:?}", result); }
* { "_id": { "month_last_active": 1 }, "number": 3 } * { "_id": { "month_last_active": 5 }, "number": 4 } * { "_id": { "month_last_active": 6 }, "number": 1 } * { "_id": { "month_last_active": 7 }, "number": 1 } * { "_id": { "month_last_active": 8 }, "number": 2 } * { "_id": { "month_last_active": 11 }, "number": 1 }
计算热门类型
以下示例根据三种最受欢迎的类型在用户兴趣中出现的频率来查找它们。
聚合管道包含以下阶段:
$unwind
阶段将genre_interests
字段中的每个大量条目分隔到新文档中$group
阶段按genre_interests
字段对文档进行群组并计算每种类型的文档数量$sort
阶段对流派受欢迎程度设立降序排序$limit
仅显示前三种类型的阶段
let popularity_pipeline = vec![ doc! { "$unwind" : "$genre_interests" }, doc! { "$group" : doc! { "_id" : "$genre_interests" , "number" : doc! { "$sum" : 1 } } }, doc! { "$sort" : doc! { "number" : -1 } }, doc! { "$limit": 3 } ]; let mut results = my_coll.aggregate(popularity_pipeline).await?; while let Some(result) = results.try_next().await? { println!("* {:?}", result); }
* { "_id": "fiction", "number": 6 } * { "_id": "memoir", "number": 5 } * { "_id": "literary", "number": 4 }
更多信息
要了解有关本指南中提到的概念的更多信息,请参阅以下服务器手册条目:
要学习;了解有关aggregate()
方法行为的详情,请参阅《检索数据》指南中的聚合操作部分。
要学习;了解有关在聚合管道中对结果进行排序的更多信息,请参阅对结果进行排序指南。
API 文档
要进一步了解本指南所提及的方法和类型,请参阅以下 API 文档: