数据库

Spring data mongo Aggregate

2018-07-17  本文已影响927人  金刚_30bf

Spring Data Mongo 支持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 的第一个参数接收一个input class , 则MongoTemplate 调用aggregate 时不需要提供collection , 若两者都提供了, 则优先使用输入的collection。

支持的聚类操作

MongoDB 本身支持的聚类操作:

Spring data mongodb 支持的:


图片.png

Projection 表达式

Projection 表达式用来定义在聚合步骤的输出结果 。 该表达式通过Aggregation类的project方法定义, 输入时String列表或Fields对象。 表达式可以通过API使用and进行扩展,使用as进行别名。 同样可以使用Fields.field静态工厂方法来定义fields。
后续聚合阶段可以使用这些fields。

例子:

// 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")


// 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")

Faceted Classification

从Mongodb 3.4版本开始, 支持分面分类faceted classification 。 它使用组合语义(一般或特殊)来创建完整的分类条目。 流经聚合管道的document被分类为多个桶。 多面分类允许在同一组输入document上进行各种聚合,而无需多次检索输入文档。

Buckets 桶

桶操作根据特定的表达式和桶边界将输入document 分组,称为桶buckets 。
桶操作需要分组字段或者分组表达式 。 使用Aggregate 类的bucket() and bucketAuto() 来定义。

BucketOperation and BucketAutoOperation 能够根据聚合表达式对输入文档进行连续处理。 可以通过fluent API 使用with 和andOutput方法来扩展桶操作。 可以通过as方法来重命名操作。 每个桶都在output以document的形式表示。

例子:

// generates {$bucket: {groupBy: $price, boundaries: [0, 100, 400]}}
bucket("price").withBoundaries(0, 100, 400);

// generates {$bucket: {groupBy: $price, default: "Other" boundaries: [0, 100]}}
bucket("price").withBoundaries(0, 100).withDefault("Other");

// generates {$bucket: {groupBy: $price, boundaries: [0, 100], output: { count: { $sum: 1}}}}
bucket("price").withBoundaries(0, 100).andOutputCount().as("count");

// generates {$bucket: {groupBy: $price, boundaries: [0, 100], 5, output: { titles: { $push: "$title"}}}
bucket("price").withBoundaries(0, 100).andOutput("title").push().as("titles");

BucketAutoOperation 自动确定边界, 尝试均匀分布 。
它支持采用粒度值, 用于确保计算的边界边缘以首选轮数或10的幂结束的首选数字序列。

// generates {$bucketAuto: {groupBy: $price, buckets: 5}}
bucketAuto("price", 5)

// generates {$bucketAuto: {groupBy: $price, buckets: 5, granularity: "E24"}}
bucketAuto("price", 5).withGranularity(Granularities.E24).withDefault("Other");

// generates {$bucketAuto: {groupBy: $price, buckets: 5, output: { titles: { $push: "$title"}}}
bucketAuto("price", 5).andOutput("title").push().as("titles");

创建输出值使用AggregationExpression 通过andOutPut() 和 SpEL表达式通过andOutputExpression()。

Multi-faceted Aggregation

可以使用多个聚合管道来创建多面聚合,以在单个聚合阶段内跨多个维度(或构面)表征数据。 多面聚合提供多个过滤器和分类,以指导数据浏览和分析。
通过Aggregation 类的 facet()方法定义一个 FacetOperation 。 可以使用and方法来自定义多个聚合管道。 每个子管道都有自己的输出。

子管道可以在分组之前投影和过滤输入文档。 常见用例包括在分类之前提取日期部分或计算。

// generates {$facet: {categorizedByPrice: [ { $match: { price: {$exists : true}}}, { $bucketAuto: {groupBy: $price, buckets: 5}}]}}
facet(match(Criteria.where("price").exists(true)), bucketAuto("price", 5)).as("categorizedByPrice"))

// generates {$facet: {categorizedByCountry: [ { $match: { country: {$exists : true}}}, { $sortByCount: "$country"}]}}
facet(match(Criteria.where("country").exists(true)), sortByCount("country")).as("categorizedByCountry"))

// generates {$facet: {categorizedByYear: [
//     { $project: { title: 1, publicationYear: { $year: "publicationDate"}}},
//     { $bucketAuto: {groupBy: $price, buckets: 5, output: { titles: {$push:"$title"}}}
// ]}}
facet(project("title").and("publicationDate").extractYear().as("publicationYear"),
      bucketAuto("publicationYear", 5).andOutput("title").push().as("titles"))
  .as("categorizedByYear"))

SpEL 表达式支持projection

在ProjectionOperation and BucketOperation类的andExpression方法中使用spEL表达式。
会将spel表达式转换为MongoDB的projection expression 。

例: 如下表达式及转换后的projection 表达式 :

1 + (q + 1) / (q - 1)
The preceding expression is translated into the following projection expression part:

{ "$add" : [ 1, {
    "$divide" : [ {
        "$add":["$q", 1]}, {
        "$subtract":[ "$q", 1]}
    ]
}]}

表达式对应关系如下:


图片.png

除此之外, 还可以在spel表达式中使用new 。

// { $setEquals : [$a, [5, 8, 13] ] }
.andExpression("setEquals(a, new int[]{5, 8, 13})");

其他聚合的使用示例参见: https://docs.spring.io/spring-data/mongodb/docs/2.0.8.RELEASE/reference/html

上一篇下一篇

猜你喜欢

热点阅读