此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Data MongoDB 4.4.0spring-doc.cadn.net.cn

聚合框架支持

Spring Data MongoDB 为版本 2.2 中引入 MongoDB 的聚合框架提供支持。spring-doc.cadn.net.cn

有关更多信息,请参阅聚合框架和 MongoDB 的其他数据聚合工具的完整参考文档spring-doc.cadn.net.cn

基本概念

Spring Data MongoDB 中的聚合框架支持基于以下关键抽象:AggregationAggregationResults.spring-doc.cadn.net.cn

  • Aggregationspring-doc.cadn.net.cn

    Aggregation表示 MongoDBaggregate作,并保存聚合管道指令的描述。聚合是通过调用适当的newAggregation(…)static factory 方法的Aggregation类,它接受一个AggregateOperation以及可选的 input 类。spring-doc.cadn.net.cn

    实际的聚合作由aggregate方法MongoTemplate,它将所需的输出类作为参数。spring-doc.cadn.net.cn

  • TypedAggregationspring-doc.cadn.net.cn

    一个TypedAggregation,就像Aggregation,包含聚合管道的指令和对 input 类型的引用,用于将域属性映射到实际文档字段。spring-doc.cadn.net.cn

    在运行时,根据给定的输入类型检查字段引用,并考虑潜在的@Field附注。spring-doc.cadn.net.cn

在 3.2 中更改:引用不存在的属性不再引发错误。要恢复之前的行为,请使用strictMapping选项AggregationOptions.spring-doc.cadn.net.cn

  • AggregationDefinitionspring-doc.cadn.net.cn

    AggregationDefinition表示 MongoDB 聚合管道作,并描述应在此聚合步骤中执行的处理。尽管您可以手动创建一个AggregationDefinition中,我们建议使用Aggregate类来构造一个AggregateOperation.spring-doc.cadn.net.cn

  • AggregationResultsspring-doc.cadn.net.cn

    AggregationResults是聚合作结果的容器。它以Document添加到映射的对象以及有关聚合的其他信息中。spring-doc.cadn.net.cn

    下面的清单显示了使用 Spring Data MongoDB 对 MongoDB 聚合框架的支持的典型示例:spring-doc.cadn.net.cn

    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从此类派生 input 集合的名称。否则,如果未指定 input 类,则必须显式提供 input 集合的名称。如果同时提供了 input 类和 input 集合,则后者优先。spring-doc.cadn.net.cn

支持的聚合作和阶段

MongoDB 聚合框架提供以下类型的聚合阶段和作:spring-doc.cadn.net.cn

不支持的聚合阶段(如 $search for MongoDB Atlas)可以通过实现AggregationOperation.Aggregation.stage是通过提供管道阶段的 JSON 或Bson表示法。spring-doc.cadn.net.cn

Aggregation.stage("""
    { $search : {
        "near": {
          "path": "released",
          "origin": { "$date": { "$numberLong": "..." } } ,
          "pivot": 7
        }
      }
    }
""");

在撰写本文时,我们为 Spring Data MongoDB 中的以下聚合运算符提供支持:spring-doc.cadn.net.cn

表 1.Spring Data MongoDB 当前支持的聚合运算符

设置聚合运算符spring-doc.cadn.net.cn

setEquals,setIntersection,setUnion,setDifference,setIsSubset,anyElementTrue,allElementsTruespring-doc.cadn.net.cn

Group/Accumulator 聚合运算符spring-doc.cadn.net.cn

addToSet,bottom,bottomN,covariancePop,covarianceSamp,expMovingAvg,first,firstN,last,lastN max,maxN,min,minN,avg,push,sum,top,topN,count(*),median,percentile,stdDevPop,stdDevSampspring-doc.cadn.net.cn

算术聚合运算符spring-doc.cadn.net.cn

abs,acos,acosh,add(* 通过plus),asin,asin,atan,atan2,atanh,ceil,cos,cosh,derivative,divide,exp,floor,integral,ln,log,log10,mod,multiply,pow,round,sqrt,subtract(* 通过minus),sin,sinh,tan,tanh,truncspring-doc.cadn.net.cn

字符串聚合运算符spring-doc.cadn.net.cn

concat,substr,toLower,toUpper,strcasecmp,indexOfBytes,indexOfCP,regexFind,regexFindAll,regexMatch,replaceAll,replaceOne, split',strLenBytes,strLenCP,substrCP,trim,ltrim,rtimspring-doc.cadn.net.cn

比较聚合运算符spring-doc.cadn.net.cn

eq(* 通过is),gt,gte,lt,lte,nespring-doc.cadn.net.cn

数组聚合运算符spring-doc.cadn.net.cn

arrayElementAt,arrayToObject,concatArrays,filter,first,in,indexOfArray,isArray,last、范围'、reverseArray,reduce,size,sortArray,slice,zipspring-doc.cadn.net.cn

文本运算符spring-doc.cadn.net.cn

literalspring-doc.cadn.net.cn

日期聚合运算符spring-doc.cadn.net.cn

dateSubstract,dateTrunc,dayOfYear,dayOfMonth,dayOfWeek,year,month,week,hour,minute,second,millisecond,dateAdd,dateDiff,dateToString,dateFromString,dateFromParts,dateToParts,isoDayOfWeek,isoWeek,isoWeekYear,tsIncrement,tsSecondspring-doc.cadn.net.cn

变量运算符spring-doc.cadn.net.cn

mapspring-doc.cadn.net.cn

条件聚合运算符spring-doc.cadn.net.cn

cond,ifNull,switchspring-doc.cadn.net.cn

类型聚合运算符spring-doc.cadn.net.cn

typespring-doc.cadn.net.cn

转换聚合运算符spring-doc.cadn.net.cn

convert,degreesToRadians,toBool,toDate,toDecimal,toDouble,toInt,toLong,toObjectId,toStringspring-doc.cadn.net.cn

对象聚合运算符spring-doc.cadn.net.cn

objectToArray,mergeObjects,getField,setFieldspring-doc.cadn.net.cn

脚本聚合运算符spring-doc.cadn.net.cn

function,accumulatorspring-doc.cadn.net.cn

* 该作由 Spring Data MongoDB 映射或添加。spring-doc.cadn.net.cn

请注意,Spring Data MongoDB 当前不支持此处未列出的聚合作。比较聚合运算符表示为Criteria表达 式。spring-doc.cadn.net.cn

投影表达式

投影表达式用于定义作为特定聚合步骤结果的字段。投影表达式可以通过project方法Aggregation类,或者通过传递String对象或聚合框架Fields对象。通过使用 Fluent API ,可以使用and(String)方法,并使用as(String)方法。 请注意,您还可以使用Fields.fieldstatic factory 方法,然后您可以使用该方法构造一个新的Fields实例。在后续聚合阶段中对投影字段的引用仅对包含的字段或其别名(包括新定义的字段及其别名)的字段名称有效。投影中未包含的字段不能在以后的聚合阶段中引用。以下清单显示了 projection 表达式的示例:spring-doc.cadn.net.cn

示例 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")

项目作的更多示例可以在AggregationTests类。请注意,有关投影表达式的更多详细信息,请参阅 MongoDB 聚合框架参考文档的相应部分spring-doc.cadn.net.cn

分面分类

从版本 3.4 开始,MongoDB 支持使用聚合框架进行分面分类。分面分类使用语义类别(常规或特定于主题),这些类别组合在一起以创建完整的分类条目。流经聚合管道的文档被分类到存储桶中。多方面分类支持对同一组输入文档进行各种聚合,而无需多次检索输入文档。spring-doc.cadn.net.cn

存储桶作根据指定的表达式和存储桶边界将传入文档分类为多个组,称为存储桶。存储桶作需要分组字段或分组表达式。您可以使用bucket()bucketAuto()的方法Aggregate类。BucketOperationBucketAutoOperation可以根据输入文档的聚合表达式公开累积。您可以通过 Fluent API 使用with…()方法和andOutput(String)方法。您可以使用as(String)方法。每个存储桶在输出中都表示为一个文档。spring-doc.cadn.net.cn

BucketOperation采用一组定义的边界,将传入文档分组到这些类别中。边界需要排序。以下清单显示了存储桶作的一些示例:spring-doc.cadn.net.cn

例 3.存储桶作示例
// 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确定边界,以尝试将文档均匀分配到指定数量的存储桶中。BucketAutoOperation(可选)采用一个粒度值,该值指定用于确保计算的边界边以首选整数或 10 的幂结束。以下清单显示了存储桶作的示例:spring-doc.cadn.net.cn

示例 4.存储桶作示例
// 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().spring-doc.cadn.net.cn

请注意,有关存储桶表达式的更多详细信息,请参阅$bucket部分$bucketAuto部分MongoDB 聚合框架参考文档。spring-doc.cadn.net.cn

多方位聚合

多个聚合管道可用于创建多方面聚合,以描述单个聚合阶段中多个维度(或分面)的数据特征。多方面聚合提供了多个筛选条件和分类,以指导数据浏览和分析。分面的常见实现是,许多在线零售商通过对产品价格、制造商、大小和其他因素应用筛选器来缩小搜索结果的范围。spring-doc.cadn.net.cn

您可以定义FacetOperation通过使用facet()方法Aggregation类。您可以使用and()方法。每个子管道在输出文档中都有自己的字段,其结果作为文档数组存储。spring-doc.cadn.net.cn

子管道可以在分组之前投影和筛选输入文档。常见用例包括在分类之前提取日期部分或计算。以下清单显示了 facet作示例:spring-doc.cadn.net.cn

例 5.Facet作示例
// 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"))

请注意,有关分面作的更多详细信息,请参阅$facet部分MongoDB 聚合框架参考文档。spring-doc.cadn.net.cn

按计数排序

按计数排序作根据指定表达式的值对传入文档进行分组,计算每个不同组中的文档计数,并按计数对结果进行排序。它提供了一个方便的快捷方式,用于在使用分面分类时应用排序。按计数排序作需要分组字段或分组表达式。以下清单显示了一个按计数排序的示例:spring-doc.cadn.net.cn

例 6.按计数排序示例
// generates { $sortByCount: "$country" }
sortByCount("country");

按计数排序作等效于以下 BSON(二进制 JSON):spring-doc.cadn.net.cn

{ $group: { _id: <expression>, count: { $sum: 1 } } },
{ $sort: { count: -1 } }

投影表达式中的 Spring 表达式支持

我们支持在投影表达式中使用 SpEL 表达式,方法是通过andExpression方法ProjectionOperationBucketOperation类。此功能允许您将所需的表达式定义为 SPEL 表达式。在运行查询时,SpEL 表达式将转换为相应的 MongoDB 投影表达式部分。这种安排使表达复杂的计算变得更加容易。spring-doc.cadn.net.cn

使用 SPEL 表达式进行复杂计算

考虑以下 SPEL 表达式:spring-doc.cadn.net.cn

1 + (q + 1) / (q - 1)

上述表达式将转换为以下 projection 表达式部分:spring-doc.cadn.net.cn

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

您可以在 Aggregation Framework Example 5Aggregation Framework Example 6 中查看更多上下文的示例。 您可以在SpelExpressionTransformerUnitTests.spring-doc.cadn.net.cn

支持的 SPEL 转换
SPEL 表达式 Mongo 表达式部分

a == bspring-doc.cadn.net.cn

{ $eq : [$a, $b] }spring-doc.cadn.net.cn

a != bspring-doc.cadn.net.cn

{ $ne : [$a , $b] }spring-doc.cadn.net.cn

a > bspring-doc.cadn.net.cn

{ $gt : [$a, $b] }spring-doc.cadn.net.cn

a >= bspring-doc.cadn.net.cn

{ $gte : [$a, $b] }spring-doc.cadn.net.cn

a < bspring-doc.cadn.net.cn

{ $lt : [$a, $b] }spring-doc.cadn.net.cn

a ⇐ bspring-doc.cadn.net.cn

{ $lte : [$a, $b] }spring-doc.cadn.net.cn

a + bspring-doc.cadn.net.cn

{ $add : [$a, $b] }spring-doc.cadn.net.cn

一 - 乙spring-doc.cadn.net.cn

{ $subtract : [$a, $b] }spring-doc.cadn.net.cn

a * bspring-doc.cadn.net.cn

{ $multiply : [$a, $b] }spring-doc.cadn.net.cn

一个 / bspring-doc.cadn.net.cn

{ $divide : [$a, $b] }spring-doc.cadn.net.cn

a^bspring-doc.cadn.net.cn

{ $pow : [$a, $b] }spring-doc.cadn.net.cn

a % bspring-doc.cadn.net.cn

{ $mod : [$a, $b] }spring-doc.cadn.net.cn

a & bspring-doc.cadn.net.cn

{ $and : [$a, $b] }spring-doc.cadn.net.cn

一个 ||bspring-doc.cadn.net.cn

{ $or : [$a, $b] }spring-doc.cadn.net.cn

!一个spring-doc.cadn.net.cn

{ $not : [$a] }spring-doc.cadn.net.cn

除了上表所示的转换之外,您还可以使用标准 SPEL作,例如newto (例如) 创建数组并通过它们的名称引用表达式(后跟括号中要使用的参数)。下面的示例演示如何以这种方式创建数组:spring-doc.cadn.net.cn

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

聚合框架示例

本节中的示例演示了 MongoDB 聚合框架与 Spring Data MongoDB 的使用模式。spring-doc.cadn.net.cn

聚合框架示例 1

在这个介绍性示例中,我们希望聚合一个标签列表,以从 MongoDB 集合(称为tags) 按出现次数降序排序。此示例演示了分组、排序、投影 (选择) 和展开 (结果拆分) 的用法。spring-doc.cadn.net.cn

class TagCount {
 String tag;
 int n;
}
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;

Aggregation agg = newAggregation(
    project("tags"),
    unwind("tags"),
    group("tags").count().as("n"),
    project("n").and("tag").previousOperation(),
    sort(DESC, "n")
);

AggregationResults<TagCount> results = mongoTemplate.aggregate(agg, "tags", TagCount.class);
List<TagCount> tagCount = results.getMappedResults();

前面的清单使用以下算法:spring-doc.cadn.net.cn

  1. 使用newAggregationstatic Factory 方法,我们将聚合作列表传递给它。这些聚合作定义了我们的Aggregation.spring-doc.cadn.net.cn

  2. 使用project作以选择tagsfield (这是一个字符串数组) 。spring-doc.cadn.net.cn

  3. 使用unwind作为tags数组。spring-doc.cadn.net.cn

  4. 使用group作为每个tags值(通过使用countaggregation 运算符并将结果收集到名为n).spring-doc.cadn.net.cn

  5. 选择n字段,并为从上一个 group作生成的 ID 字段创建别名(因此对previousOperation()),名称为tag.spring-doc.cadn.net.cn

  6. 使用sort作按标签的出现次数降序对生成的标签列表进行排序。spring-doc.cadn.net.cn

  7. 调用aggregatemethod 开启MongoTemplate让 MongoDB 执行实际的聚合作,使用创建的Aggregation作为参数。spring-doc.cadn.net.cn

请注意,输入集合被显式指定为tags参数添加到aggregate方法。如果未显式指定 input 集合的名称,则它是从作为第一个参数传递给newAggreation方法。spring-doc.cadn.net.cn

聚合框架示例 2

此示例基于 MongoDB 聚合框架文档中的各州最大和最小城市示例。我们添加了额外的排序,以便在不同的 MongoDB 版本中产生稳定的结果。在这里,我们希望使用聚合框架返回每个州的人口数量最小和最大的城市。此示例演示了分组、排序和投影 (选择)。spring-doc.cadn.net.cn

class ZipInfo {
   String id;
   String city;
   String state;
   @Field("pop") int population;
   @Field("loc") double[] location;
}

class City {
   String name;
   int population;
}

class ZipInfoStats {
   String id;
   String state;
   City biggestCity;
   City smallestCity;
}
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;

TypedAggregation<ZipInfo> aggregation = newAggregation(ZipInfo.class,
    group("state", "city")
       .sum("population").as("pop"),
    sort(ASC, "pop", "state", "city"),
    group("state")
       .last("city").as("biggestCity")
       .last("pop").as("biggestPop")
       .first("city").as("smallestCity")
       .first("pop").as("smallestPop"),
    project()
       .and("state").previousOperation()
       .and("biggestCity")
          .nested(bind("name", "biggestCity").and("population", "biggestPop"))
       .and("smallestCity")
          .nested(bind("name", "smallestCity").and("population", "smallestPop")),
    sort(ASC, "state")
);

AggregationResults<ZipInfoStats> result = mongoTemplate.aggregate(aggregation, ZipInfoStats.class);
ZipInfoStats firstZipInfoStats = result.getMappedResults().get(0);

请注意,ZipInfoclass 映射给定 input-collection 的结构。这ZipInfoStatsclass 以所需的输出格式定义结构。spring-doc.cadn.net.cn

前面的清单使用以下算法:spring-doc.cadn.net.cn

  1. 使用group作从 input-collection 中定义一个组。分组标准是statecity字段,它构成了组的 ID 结构。我们将population属性,方法是使用sum运算符并将结果保存在pop田。spring-doc.cadn.net.cn

  2. 使用sort作对中间结果进行排序pop,statecity字段,以便最小的城市位于结果的顶部,最大的城市位于结果的底部。请注意,对statecity针对组 ID 字段(Spring Data MongoDB 处理)隐式执行。spring-doc.cadn.net.cn

  3. 使用group作,将中间结果分组state.请注意,state再次隐式引用组 ID 字段。我们选择最大和最小城市的名称和人口计数,并调用last(…)first(…​)运算符,分别在project操作。spring-doc.cadn.net.cn

  4. 选择state字段group操作。请注意,state再次隐式引用组 ID 字段。因为我们不希望隐式生成的 ID 出现,所以我们使用and(previousOperation()).exclude().因为我们想要填充嵌套的City结构体中,我们必须使用 Nested 方法发出适当的子文档。spring-doc.cadn.net.cn

  5. 对生成的StateStats按其状态名称在sort操作。spring-doc.cadn.net.cn

请注意,我们从ZipInfo类作为第一个参数传递给newAggregation方法。spring-doc.cadn.net.cn

聚合框架示例 3

此示例基于 MongoDB 聚合框架文档中的人口超过 1000 万的州示例。我们添加了额外的排序,以便在不同的 MongoDB 版本中产生稳定的结果。在这里,我们希望使用聚合框架返回人口超过 1000 万的所有州。此示例演示了分组、排序和匹配(筛选)。spring-doc.cadn.net.cn

class StateStats {
   @Id String id;
   String state;
   @Field("totalPop") int totalPopulation;
}
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;

TypedAggregation<ZipInfo> agg = newAggregation(ZipInfo.class,
    group("state").sum("population").as("totalPop"),
    sort(ASC, previousOperation(), "totalPop"),
    match(where("totalPop").gte(10 * 1000 * 1000))
);

AggregationResults<StateStats> result = mongoTemplate.aggregate(agg, StateStats.class);
List<StateStats> stateStatsList = result.getMappedResults();

前面的清单使用以下算法:spring-doc.cadn.net.cn

  1. state字段并计算population字段并将结果存储在新字段中"totalPop".spring-doc.cadn.net.cn

  2. 除了"totalPop"字段。spring-doc.cadn.net.cn

  3. 使用match作,该作接受Criteriaquery 作为参数。spring-doc.cadn.net.cn

请注意,我们从ZipInfo类作为第一个参数传递给newAggregation方法。spring-doc.cadn.net.cn

聚合框架示例 4

此示例演示了在投影运算中使用简单的算术运算。spring-doc.cadn.net.cn

class Product {
    String id;
    String name;
    double netPrice;
    int spaceUnits;
}
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;

TypedAggregation<Product> agg = newAggregation(Product.class,
    project("name", "netPrice")
        .and("netPrice").plus(1).as("netPricePlus1")
        .and("netPrice").minus(1).as("netPriceMinus1")
        .and("netPrice").multiply(1.19).as("grossPrice")
        .and("netPrice").divide(2).as("netPriceDiv2")
        .and("spaceUnits").mod(2).as("spaceUnitsMod2")
);

AggregationResults<Document> result = mongoTemplate.aggregate(agg, Document.class);
List<Document> resultList = result.getMappedResults();

请注意,我们从Product类作为第一个参数传递给newAggregation方法。spring-doc.cadn.net.cn

聚合框架示例 5

此示例演示了在投影运算中使用从 SpEL 表达式派生的简单算术运算。spring-doc.cadn.net.cn

class Product {
    String id;
    String name;
    double netPrice;
    int spaceUnits;
}
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;

TypedAggregation<Product> agg = newAggregation(Product.class,
    project("name", "netPrice")
        .andExpression("netPrice + 1").as("netPricePlus1")
        .andExpression("netPrice - 1").as("netPriceMinus1")
        .andExpression("netPrice / 2").as("netPriceDiv2")
        .andExpression("netPrice * 1.19").as("grossPrice")
        .andExpression("spaceUnits % 2").as("spaceUnitsMod2")
        .andExpression("(netPrice * 0.8  + 1.2) * 1.19").as("grossPriceIncludingDiscountAndCharge")

);

AggregationResults<Document> result = mongoTemplate.aggregate(agg, Document.class);
List<Document> resultList = result.getMappedResults();

聚合框架示例 6

此示例演示了在投影运算中使用从 SpEL 表达式派生的复杂算术运算。spring-doc.cadn.net.cn

注意:传递给addExpressionmethod 可以根据它们的位置使用索引器表达式进行引用。在此示例中,我们使用[0].当 SPEL 表达式转换为 MongoDB 聚合框架表达式时,外部参数表达式将替换为它们各自的值。spring-doc.cadn.net.cn

class Product {
    String id;
    String name;
    double netPrice;
    int spaceUnits;
}
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;

double shippingCosts = 1.2;

TypedAggregation<Product> agg = newAggregation(Product.class,
    project("name", "netPrice")
        .andExpression("(netPrice * (1-discountRate)  + [0]) * (1+taxRate)", shippingCosts).as("salesPrice")
);

AggregationResults<Document> result = mongoTemplate.aggregate(agg, Document.class);
List<Document> resultList = result.getMappedResults();

请注意,我们还可以在 SPEL 表达式中引用文档的其他字段。spring-doc.cadn.net.cn

聚合框架示例 7

此示例使用条件投影。它源自 $cond 参考文档spring-doc.cadn.net.cn

public class InventoryItem {

  @Id int id;
  String item;
  String description;
  int qty;
}

public class InventoryItemProjection {

  @Id int id;
  String item;
  String description;
  int qty;
  int discount
}
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;

TypedAggregation<InventoryItem> agg = newAggregation(InventoryItem.class,
  project("item").and("discount")
    .applyCondition(ConditionalOperator.newBuilder().when(Criteria.where("qty").gte(250))
      .then(30)
      .otherwise(20))
    .and(ifNull("description", "Unspecified")).as("description")
);

AggregationResults<InventoryItemProjection> result = mongoTemplate.aggregate(agg, "inventory", InventoryItemProjection.class);
List<InventoryItemProjection> stateStatsList = result.getMappedResults();

此单步聚合使用具有inventory收集。我们投影discount字段,方法是对具有qty大于或等于250.对description田。我们应用Unspecifieddescription 添加到没有description字段或具有null描述。spring-doc.cadn.net.cn

从 MongoDB 3.6 开始,可以使用条件表达式从投影中排除字段。spring-doc.cadn.net.cn

例 7.条件聚合投影
TypedAggregation<Book> agg = Aggregation.newAggregation(Book.class,
  project("title")
    .and(ConditionalOperators.when(ComparisonOperators.valueOf("author.middle")     (1)
        .equalToValue(""))                                                          (2)
        .then("$$REMOVE")                                                           (3)
        .otherwiseValueOf("author.middle")                                          (4)
    )
	.as("author.middle"));
1 如果字段的值author.middle
2 不包含值,
3 然后使用$$REMOVE以排除该字段。
4 否则,请添加author.middle.