Spring data mongo Aggregate

Spring Data Mongo 支持MongoDB引入的聚类框架。

基本概念

  • Aggregation : 聚类 ,表示MongoDB的aggregate 操作,它保存aggregation Pipeline的命令。 通过Aggregation类类表示, 该类有一个AggregateOperation列表和其他输入类。
    实际执行过程是通过MongoTemplate 来执行的。

  • AggregationOperation 聚类操作: 表示一个MongoDB aggregation pipeline 操作,描述聚类执行的步骤 。 尽管可以手工创建一个AggregationOperation , 但是建议使用Aggregate类提供的静态工厂方法来创建。

  • AggregationResults 聚类结果: 聚类操作的结果容器。 提供以document形式访问的操作。

如下示例是一个典型的聚类操作:

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 本身支持的聚类操作:

  • Pipeline Aggregation Operators

  • Group Aggregation Operators

  • Boolean Aggregation Operators

  • Comparison Aggregation Operators

  • Arithmetic Aggregation Operators

  • String Aggregation Operators

  • Date Aggregation Operators

  • Array Aggregation Operators

  • Conditional Aggregation Operators

  • Lookup Aggregation Operators

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 224,467评论 6 522
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,079评论 3 402
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 171,600评论 0 366
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 60,835评论 1 300
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 69,848评论 6 399
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,348评论 1 314
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,735评论 3 428
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,705评论 0 279
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,238评论 1 324
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,268评论 3 345
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,395评论 1 354
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,012评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,704评论 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,177评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,309评论 1 275
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,925评论 3 381
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,457评论 2 365

推荐阅读更多精彩内容