聚合
概述
在本指南中,您可以学习如何在Rust驱动程序中执行聚合操作。
聚合操作根据您可以在聚合管道中设置的规范处理MongoDB集合中的数据。聚合管道由一个或多个阶段组成。每个阶段根据其表达式运算符执行操作。驱动程序执行聚合管道后,返回聚合结果。
本指南包括以下部分
比较聚合操作和查找操作描述了聚合操作和查找操作之间的功能差异
服务器限制描述了服务器对聚合操作内存使用的限制
示例提供了不同用例的聚合示例
更多信息提供了本指南中提到的类型和方法的资源链接和API文档
类比
聚合操作与汽车工厂的装配线类似。装配线有配备专用工具的工作站,以执行特定任务。例如,在组装汽车时,装配线从车架开始。然后,随着车架在装配线上移动,每个工作站组装一个单独的部件。结果是变换后的最终产品,即完成的汽车。
装配线代表聚合管道,单个工作站代表聚合阶段,专用工具代表表达式运算符,最终产品代表聚合结果。
比较聚合操作和查找操作
以下表格列出了您可以使用查找操作执行的不同任务,以及您可以使用聚合操作实现的内容。聚合框架提供扩展功能,允许您转换和操作您的数据。
查找操作 | 聚合操作 |
---|---|
选择返回的特定文档 选择返回的字段 排序结果 限制结果 计数结果 | 选择返回的特定文档 选择返回的字段 排序结果 限制结果 计数结果 重命名字段 计算新字段 总结数据 连接和合并数据集 |
服务器限制
执行聚合操作时,请考虑以下限制
返回的文档不得违反BSON 文档大小限制为16兆字节。
默认情况下,管道阶段具有100MB的内存限制。如有需要,您可以通过设置 allow_disk_use 字段来超过此限制。
AggregateOptions
.$graphLookup 操作符有一个严格的100MB内存限制,并忽略
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文档