文档菜单
文档首页
/ / /
Java 同步驱动程序
/

聚合

本页内容

  • 概述
  • 比较聚合和查找操作
  • 有用参考
  • 可运行示例
  • 导入类
  • 基本聚合示例
  • 解释聚合示例
  • 聚合表达式示例

在本指南中,您可以了解如何使用Java驱动程序执行聚合操作

聚合操作处理MongoDB集合中的数据,并返回计算结果。MongoDB聚合框架是查询API的一部分,基于数据处理管道的概念。文档进入由一个或多个阶段组成的管道,这个管道将文档转换成聚合结果。

聚合操作类似于汽车工厂。汽车工厂有一条装配线,包含装配站和专用工具来完成特定的任务,如钻孔和焊接。原材料进入工厂,然后装配线将它们转换和组装成成品。

聚合管道是装配线,聚合阶段是装配站,而操作表达式是专用工具。

您可以使用查找操作执行以下操作

  • 选择要返回的文档

  • 选择要返回的字段

  • 排序结果

您可以使用聚合操作执行以下操作

  • 执行查找操作

  • 重命名字段

  • 计算字段

  • 汇总数据

  • 分组值

聚合操作有一些限制您需要注意

  • 返回的文档不能违反16兆字节的BSON文档大小限制

  • 默认情况下,流水线阶段有100兆字节的内存限制。如果需要,您可以通过使用allowDiskUse方法来超出此限制。

    重要

    $graphLookup异常

    $graphLookup阶段有严格的100兆字节内存限制,并将忽略allowDiskUse.

  • 聚合管道

  • 聚合阶段

  • 运算符表达式

  • 聚合构建器

创建一个名为 AggTour.java 的新 Java 文件,并包含以下导入语句

import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.ExplainVerbosity;
import com.mongodb.client.model.Accumulators;
import com.mongodb.client.model.Aggregates;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Projections;
import org.bson.Document;
import org.bson.json.JsonWriterSettings;
import java.util.Arrays;
import java.util.List;
public class AggTour {
public static void main(String[] args) {
// Replace the uri string with your MongoDB deployment's connection string
String uri = "<connection string>";
MongoClient mongoClient = MongoClients.create(uri);
MongoDatabase database = mongoClient.getDatabase("aggregation");
MongoCollection<Document> collection = database.getCollection("restaurants");
// Paste the aggregation code here
}
}

提示

要了解有关连接到 MongoDB 的更多信息,请参阅连接指南。

collection.insertMany(Arrays.asList(
new Document("name", "Sun Bakery Trattoria").append("contact", new Document().append("phone", "386-555-0189").append("email", "SunBakeryTrattoria@example.org").append("location", Arrays.asList(-74.0056649, 40.7452371))).append("stars", 4).append("categories", Arrays.asList("Pizza", "Pasta", "Italian", "Coffee", "Sandwiches")),
new Document("name", "Blue Bagels Grill").append("contact", new Document().append("phone", "786-555-0102").append("email", "BlueBagelsGrill@example.com").append("location", Arrays.asList(-73.92506, 40.8275556))).append("stars", 3).append("categories", Arrays.asList("Bagels", "Cookies", "Sandwiches")),
new Document("name", "XYZ Bagels Restaurant").append("contact", new Document().append("phone", "435-555-0190").append("email", "XYZBagelsRestaurant@example.net").append("location", Arrays.asList(-74.0707363, 40.59321569999999))).append("stars", 4).append("categories", Arrays.asList("Bagels", "Sandwiches", "Coffee")),
new Document("name", "Hot Bakery Cafe").append("contact", new Document().append("phone", "264-555-0171").append("email", "HotBakeryCafe@example.net").append("location", Arrays.asList(-73.96485799999999, 40.761899))).append("stars", 4).append("categories", Arrays.asList("Bakery", "Cafe", "Coffee", "Dessert")),
new Document("name", "Green Feast Pizzeria").append("contact", new Document().append("phone", "840-555-0102").append("email", "GreenFeastPizzeria@example.com").append("location", Arrays.asList(-74.1220973, 40.6129407))).append("stars", 2).append("categories", Arrays.asList("Pizza", "Italian")),
new Document("name", "ZZZ Pasta Buffet").append("contact", new Document().append("phone", "769-555-0152").append("email", "ZZZPastaBuffet@example.com").append("location", Arrays.asList(-73.9446421, 40.7253944))).append("stars", 0).append("categories", Arrays.asList("Pasta", "Italian", "Buffet", "Cafeteria")),
new Document("name", "XYZ Coffee Bar").append("contact", new Document().append("phone", "644-555-0193").append("email", "XYZCoffeeBar@example.net").append("location", Arrays.asList(-74.0166091, 40.6284767))).append("stars", 5).append("categories", Arrays.asList("Coffee", "Cafe", "Bakery", "Chocolates")),
new Document("name", "456 Steak Restaurant").append("contact", new Document().append("phone", "990-555-0165").append("email", "456SteakRestaurant@example.com").append("location", Arrays.asList(-73.9365108, 40.8497077))).append("stars", 0).append("categories", Arrays.asList("Steak", "Seafood")),
new Document("name", "456 Cookies Shop").append("contact", new Document().append("phone", "604-555-0149").append("email", "456CookiesShop@example.org").append("location", Arrays.asList(-73.8850023, 40.7494272))).append("stars", 4).append("categories", Arrays.asList("Bakery", "Cookies", "Cake", "Coffee")),
new Document("name", "XYZ Steak Buffet").append("contact", new Document().append("phone", "229-555-0197").append("email", "XYZSteakBuffet@example.org").append("location", Arrays.asList(-73.9799932, 40.7660886))).append("stars", 3).append("categories", Arrays.asList("Steak", "Salad", "Chinese"))
));

要执行聚合,请将聚合阶段列表传递给 MongoCollection.aggregate() 方法。

Java 驱动提供了Aggregates 辅助类,其中包含聚合阶段的构建器。

在以下示例中,聚合管道

  • 使用一个 $match 阶段来过滤包含元素 Bakerycategories 数组字段的文档。示例使用 Aggregates.match 来构建 $match 阶段。

  • 使用一个 $group 阶段按 stars 字段分组匹配的文档,累计每个不同的 stars 值的文档计数。

注意

您可以使用 聚合构建器构建此示例中使用的表达式。

collection.aggregate(
Arrays.asList(
Aggregates.match(Filters.eq("categories", "Bakery")),
Aggregates.group("$stars", Accumulators.sum("count", 1))
)
// Prints the result of the aggregation operation as JSON
).forEach(doc -> System.out.println(doc.toJson()));

前面的聚合产生以下结果

{"_id": 4, "count": 2}
{"_id": 5, "count": 1}

有关本节中提到的方法和类的更多信息,请参阅以下API文档

要查看MongoDB执行操作的信息,请使用explain()方法,该方法属于AggregateIterable类。explain()方法返回执行计划和性能统计信息。执行计划是MongoDB完成操作的一种潜在方式。explain()方法提供了获胜的计划,即MongoDB执行的计划,以及任何被拒绝的计划。

提示

有关查询计划和执行统计的更多信息,请参阅服务器手册中的解释结果

您可以通过向explain()方法传递一个详细程度级别来指定解释的详细程度。

以下表格显示了所有详细程度级别及其预期的使用场景

详细程度级别
使用场景
ALL_PLANS_EXECUTIONS
您想了解MongoDB将选择哪个计划来运行您的查询。
EXECUTION_STATS
您想了解您的查询是否表现良好。
QUERY_PLANNER
您遇到查询问题,并希望尽可能多地获取信息以诊断问题。

以下示例打印了任何产生执行计划的聚合阶段的获胜计划的JSON表示

Document explanation = collection.aggregate(
Arrays.asList(
Aggregates.match(Filters.eq("categories", "Bakery")),
Aggregates.group("$stars", Accumulators.sum("count", 1))
)
).explain(ExplainVerbosity.EXECUTION_STATS);
String winningPlans = explanation
.getEmbedded(
Arrays.asList("queryPlanner", "winningPlan", "queryPlan"),
Document.class
)
.toJson(JsonWriterSettings.builder().indent(true).build());
System.out.println(winningPlans);

该示例产生以下输出,因为$group阶段是唯一产生执行计划的阶段

{
"stage": "GROUP",
"planNodeId": 2,
"inputStage": {
"stage": "COLLSCAN",
"planNodeId": 1,
"filter": {
"categories": {
"$eq": "Bakery"
}
},
"direction": "forward"
}
}

有关本节中提到的主题的更多信息,请参阅以下资源

Java驱动程序为与$group一起使用的累加器表达式提供了构建器。您必须以JSON格式或兼容文档格式声明所有其他表达式。

提示

以下任一示例中的语法将定义一个$arrayElemAt表达式。

“categories”前的$告诉MongoDB这是一个字段路径,使用输入文档中的categories字段。

new Document("$arrayElemAt", Arrays.asList("$categories", 0))
Document.parse("{ $arrayElemAt: ['$categories', 0] }")

或者,您可以使用聚合表达式操作API来构造表达式。有关更多信息,请参阅聚合表达式操作。

以下示例中,聚合管道使用$project阶段和各种投影来返回name字段和计算字段firstCategory,其值为categories字段中的第一个元素。

collection.aggregate(
Arrays.asList(
Aggregates.project(
Projections.fields(
Projections.excludeId(),
Projections.include("name"),
Projections.computed(
"firstCategory",
new Document(
"$arrayElemAt",
Arrays.asList("$categories", 0)
)
)
)
)
)
).forEach(doc -> System.out.println(doc.toJson()));

前面的聚合产生以下结果

{"name": "456 Cookies Shop", "firstCategory": "Bakery"}
{"name": "Sun Bakery Trattoria", "firstCategory": "Pizza"}
{"name": "456 Steak Restaurant", "firstCategory": "Steak"}
{"name": "Blue Bagels Grill", "firstCategory": "Bagels"}
{"name": "XYZ Steak Buffet", "firstCategory": "Steak"}
{"name": "Hot Bakery Cafe", "firstCategory": "Bakery"}
{"name": "Green Feast Pizzeria", "firstCategory": "Pizza"}
{"name": "ZZZ Pasta Buffet", "firstCategory": "Pasta"}
{"name": "XYZ Coffee Bar", "firstCategory": "Coffee"}
{"name": "XYZ Bagels Restaurant", "firstCategory": "Bagels"}

有关本节中提到的方法和类的更多信息,请参阅以下API文档

返回

更新