Spring Data MongoDB 为 MongoDB 在 2.2 版本中引入的聚合框架提供支持,下面将介绍一些关于聚合框架的基础概念。
Spring Data MongoDB 中的聚合框架支持是基于以下三个关键抽象:Aggregation、AggregationDefinition 和 AggregationResults。
Aggregation 表示一个 MongoDB 的聚合操作,并保存了聚合管道指令的描述。通过调用 Aggregation 类对应的 newAggregation(…) 静态工厂方法创建聚合,该方法接受AggregateOperation 列表和可选输入类作为参数。
实际上,聚合操作是由 MongoTemplate 的 aggregate() 方法来执行,该方法将所需的输出类作为参数。
与 Aggregation 一样,TypedAggregation 包含聚合管道的指令和对输入类型的引用,输入类型用于将域属性映射到实际文档字段。在运行时,根据给定的输入类型检查字段引用,同时考虑潜在的 @Field 注解。
注意:在 3.2 版本中优速改变,引用不存在的属性时不再引发错误。如果需要恢复以前的行为,可使用 AggregationOptions 的 strictMapping 选项进行设置。
AggregationDefinition 表示 MongoDB 的聚合管道操作,并描述在此聚合步骤中应该执行的处理。尽管您可以手动创建 AggregationDefinition,但我们建议使用 Aggregate 类提供的静态工厂方法来构造 AggregateOperation。
AggregationResults 是聚合操作结果的容器。它提供了对原始聚合结果的访问,以 Document 的形式访问映射对象和关于聚合的其他信息。下面显示了使用 Spring Data MongoDB支持 MongoDB 聚合框架的典型示例:
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; Aggregation agg = newAggregation( pipelineOP1(), pipelineOP2(), pipelineOPn() ); AggregationResults<OutputType> results = mongoTemplate.aggregate(agg, "INPUT_COLLECTION_NAME", OutputType.class); List<OutputType> mappedResult = results.getMappedResults();
注意,如果你提供一个输入类作为 newAggregation 方法的第一个参数,MongoTemplate 就会从这个类派生出输入集合的名称。 否则,如果你没有指定一个输入类,你必须明确提供输入集合的名称。 如果同时提供了一个输入类和一个输入集合,则后者优先考虑。
newAggregation() 方法的定义:
static <T> TypedAggregation<T> newAggregation(Class<T> type, List<? extends AggregationOperation> operations) 为给定的类型和 AggregationOperations 创建一个新的 TypedAggregation。
static <T> TypedAggregation<T> newAggregation(Class<T> type, AggregationOperation... operations) 为给定的类型和 AggregationOperations 创建一个新的 TypedAggregation。
static Aggregation newAggregation(List<? extends AggregationOperation> operations) 从给定的 AggregationOperations 创建一个新的 Aggregation。
static Aggregation newAggregation(AggregationOperation... operations) 从给定的 AggregationOperations 创建一个新的 Aggregation。
投影表达式用于定义聚合步骤的结果字段。投影表达式可以通过向 Aggregation.project() 方法传递一个 String 列表或聚合框架的 Fields 对象来定义。投影可以通过使用 and (String) 和 as(String) 方法的别名来扩展额外的字段。
project() 方法定义如下:
static ProjectionOperation project(Class<?> type)
static ProjectionOperation project(String... fields)
static ProjectionOperation project(Fields fields)
ProjectionOperation.and() 方法定义如下:
ProjectionOperation.ProjectionOperationBuilder and(String name) 为给定名称的字段定义一个投影,创建新的 ProjectionOperation.ProjectionOperationBuilder
ProjectionOperation.ProjectionOperationBuilder and(AggregationExpression expression)
ProjectionOperation.ProjectionOperationBuilder.as() 方法定义如下:
ProjectionOperation as(String alias) 为上一次投影操作指定别名
注意:也可以通过使用聚合框架的 Fields.field() 静态工厂方法来定义带有别名的字段,然后用它来构造一个新的 Fields 实例。在后续聚合阶段对投影字段的引用仅对包含字段的字段名称或其别名(包括新定义的字段及其别名)有效。投影中未包含的字段无法在以后的聚合阶段中引用。
Fields.field() 方法定义如下:
static Field field(String name) 用给定的 name 创建一个 Field
static Field field(String name, String target) 用给定的 name 和 target 创建一个 Field
static Fields fields(String... names) 用给定的 names 创建一个 Fields
下面的列表显示了投射表达式的例子:
(1)投影表达式示例
// generates {$project: {name: 1, netPrice: 1}} project("name", "netPrice") // generates {$project: {thing1: $thing2}} project().and("thing1").as("thing2") // generates {$project: {a: 1, b: 1, thing2: $thing1}} project("a","b").and("thing1").as("thing2")
(2)使用投影和排序的多阶段聚合
// generates {$project: {name: 1, netPrice: 1}}, {$sort: {name: 1}} project("name", "netPrice"), sort(ASC, "name") // generates {$project: {name: $firstname}}, {$sort: {name: 1}} project().and("firstname").as("name"), sort(ASC, "name") // does not work project().and("firstname").as("name"), sort(ASC, "firstname")