Overview
在本指南中,您可以了解如何在 Kotlin 驱动程序中使用聚合操作。
聚合操作进程MongoDB集合中的数据并返回计算结果。MongoDB 的聚合管道是 Query API的一部分,以数据处理管道的概念为模型。文档进入多阶段管道,该管道将文档转换为聚合结果。
提示
完成聚合教程
You can find tutorials that provide detailed explanations of common aggregation tasks in the Complete Aggregation Pipeline Tutorials section of the Server manual. Select a tutorial, and then pick Kotlin (Coroutine) from the Select your language drop-down menu in the upper-right corner of the page.
类比
聚合的功能类似于汽车工厂中的功能。汽车工厂内有一条装配线,沿线有配备专门工具来完成特定作业的装配站,例如钻头和焊机。毛坯零件进入工厂,工厂将其转换并组装成成品。
聚合管道是装配线,聚合阶段是装配站,操作符表达式则是专用工具。
聚合和查找操作比较
使用find操作,您可以:
选择要返回哪些文档
选择要返回哪些字段
对结果进行排序
使用aggregation操作,您可以:
执行所有
find操作重命名字段
计算字段
汇总数据
对值进行分组
聚合操作存在一些限制,您必须牢记:
Returned documents must not violate the BSON document size limit of 16 megabytes.
默认情况下,管道阶段的内存限制为 100 MB。如果需要,可使用 allowDiskUse 方法超过此限制。
实用参考资料
示例数据
这些示例使用 MongoDB 中的以下数据的 collection:
[ {"name": "Sun Bakery Trattoria", "contact": {"phone": "386-555-0189", "email": "SunBakeryTrattoria@example.org", "location": [-74.0056649, 40.7452371]}, "stars": 4, "categories": ["Pizza", "Pasta", "Italian", "Coffee", "Sandwiches"]}, {"name": "Blue Bagels Grill", "contact": {"phone": "786-555-0102", "email": "BlueBagelsGrill@example.com", "location": [-73.92506, 40.8275556]}, "stars": 3, "categories": ["Bagels", "Cookies", "Sandwiches"]}, {"name": "XYZ Bagels Restaurant", "contact": {"phone": "435-555-0190", "email": "XYZBagelsRestaurant@example.net", "location": [-74.0707363, 40.59321569999999]}, "stars": 4, "categories": ["Bagels", "Sandwiches", "Coffee"]}, {"name": "Hot Bakery Cafe", "contact": {"phone": "264-555-0171", "email": "HotBakeryCafe@example.net", "location": [-73.96485799999999, 40.761899]}, "stars": 4, "categories": ["Bakery", "Cafe", "Coffee", "Dessert"]}, {"name": "Green Feast Pizzeria", "contact": {"phone": "840-555-0102", "email": "GreenFeastPizzeria@example.com", "location": [-74.1220973, 40.6129407]}, "stars": 2, "categories": ["Pizza", "Italian"]}, {"name": "ZZZ Pasta Buffet", "contact": {"phone": "769-555-0152", "email": "ZZZPastaBuffet@example.com", "location": [-73.9446421, 40.7253944]}, "stars": 0, "categories": ["Pasta", "Italian", "Buffet", "Cafeteria"]}, {"name": "XYZ Coffee Bar", "contact": {"phone": "644-555-0193", "email": "XYZCoffeeBar@example.net", "location": [-74.0166091, 40.6284767]}, "stars": 5, "categories": ["Coffee", "Cafe", "Bakery", "Chocolates"]}, {"name": "456 Steak Restaurant", "contact": {"phone": "990-555-0165", "email": "456SteakRestaurant@example.com", "location": [-73.9365108, 40.8497077]}, "stars": 0, "categories": ["Steak", "Seafood"]}, {"name": "456 Cookies Shop", "contact": {"phone": "604-555-0149", "email": "456CookiesShop@example.org", "location": [-73.8850023, 40.7494272]}, "stars": 4, "categories": ["Bakery", "Cookies", "Cake", "Coffee"]}, {"name": "XYZ Steak Buffet", "contact": {"phone": "229-555-0197", "email": "XYZSteakBuffet@example.org", "location": [-73.9799932, 40.7660886]}, "stars": 3, "categories": ["Steak", "Salad", "Chinese"]} ]
collection中的数据由以下Restaurant数据类进行建模:
data class Restaurant( val name: String, val contact: Contact, val stars: Int, val categories: List<String> ) { data class Contact( val phone: String, val email: String, val location: List<Double> ) }
基本聚合
如需执行聚合,请向 MongoCollection.aggregate() 方法传递聚合阶段列表。
Kotlin驱动程序提供了 Aggregates 辅助类,其中包含聚合阶段的构建者。
在以下示例中,聚合管道:
Uses a $match stage to filter for documents whose
categoriesarray field contains the elementBakery. The example usesAggregates.matchto build the$matchstage.Uses a $group stage to group the matching documents by the
starsfield, accumulating a count of documents for each distinct value ofstars.
提示
您可以使用聚合构建者构建此示例中使用的表达式。
data class Results( val id: Int, val count: Int) val resultsFlow = collection.aggregate<Results>( listOf( Aggregates.match(Filters.eq(Restaurant::categories.name, "Bakery")), Aggregates.group( "\$${Restaurant::stars.name}", Accumulators.sum("count", 1) ) ) ) resultsFlow.collect { println(it) }
Results(id=4, count=2) Results(id=5, count=1)
有关本节中提到的方法和类的详情,请参阅以下 API 文档:
解释聚合
要查看有关 MongoDB 如何执行您的操作的信息,请使用 AggregateFlow 类的 explain() 方法。explain() 方法返回执行计划和性能统计信息。执行计划是 MongoDB 完成操作的一种潜在方式。explain() 方法同时提供获胜计划(即 MongoDB 执行的计划)和被拒绝的计划。
您可以通过将详细程度传递给 explain() 方法来指定说明的详细程度。
下表显示了说明的所有详细级别及其预计使用案例:
详细程度 | 用例(Use Case) |
|---|---|
ALL_PLANS_EXECUTIONS | 你想知道 MongoDB 会选择哪个计划来运行查询。 |
EXECUTION_STATS | 您想知道您的查询是否表现良好。 |
QUERY_PLANNER | 您的查询有问题,需要尽可能多的信息来诊断问题。 |
在以下示例中,我们将打印生成执行计划的聚合阶段的获胜计划的 JSON 表示形式:
data class Results(val name: String, val count: Int) val explanation = collection.aggregate<Results>( listOf( Aggregates.match(Filters.eq(Restaurant::categories.name, "bakery")), Aggregates.group("\$${Restaurant::stars.name}", Accumulators.sum("count", 1)) ) ).explain(ExplainVerbosity.EXECUTION_STATS) // Prettyprint the output println(explanation.toJson(JsonWriterSettings.builder().indent(true).build()))
{ "explainVersion": "2", "queryPlanner": { // ... }, "command": { // ... }, // ... }
有关本节提及主题的更多信息,请参阅以下资源:
解释输出服务器手册条目
查询计划服务器手册条目
ExplainVerbosity API 文档
解释() API 文档
AggregateFlow API文档
聚合表达式
Kotlin 驱动程序提供了与 $group 一起使用的累加器表达式的构建器。您必须以 JSON 格式或兼容的文档格式声明所有其他表达式。
提示
下面任一示例中的语法都将定义一个 $arrayElemAt 表达式。
“类别”前面的$告诉 MongoDB 这是一个字段路径,使用输入文档中的“类别”字段。
Document("\$arrayElemAt", listOf("\$categories", 0)) // is equivalent to Document.parse("{ \$arrayElemAt: ['\$categories', 0] }")
在以下示例中,聚合管道使用 $project 阶段和各种 Projections 来返回 name 字段和计算字段 firstCategory,其值是 categories 字段中的第一个元素。
data class Results(val name: String, val firstCategory: String) val resultsFlow = collection.aggregate<Results>( listOf( Aggregates.project( Projections.fields( Projections.excludeId(), Projections.include("name"), Projections.computed( "firstCategory", Document("\$arrayElemAt", listOf("\$categories", 0)) ) ) ) ) ) resultsFlow.collect { println(it) }
Results(name=Sun Bakery Trattoria, firstCategory=Pizza) Results(name=Blue Bagels Grill, firstCategory=Bagels) Results(name=XYZ Bagels Restaurant, firstCategory=Bagels) Results(name=Hot Bakery Cafe, firstCategory=Bakery) Results(name=Green Feast Pizzeria, firstCategory=Pizza) Results(name=ZZZ Pasta Buffet, firstCategory=Pasta) Results(name=XYZ Coffee Bar, firstCategory=Coffee) Results(name=456 Steak Restaurant, firstCategory=Steak) Results(name=456 Cookies Shop, firstCategory=Bakery) Results(name=XYZ Steak Buffet, firstCategory=Steak)
API 文档
有关本节中提到的方法和类的详情,请参阅以下 API 文档: