该示例演示了在投影操作中使用从 Sp-EL 表达式派生的复杂算术运算。
注意:传递给 addExpression() 方法的其他参数可以根据索引器表达式的位置引用。在此示例中,我们使用 [0] 引用参数数组的第一个参数。当 SpEL 表达式转换为 MongoDB 聚合框架表达式时,外部参数表达式将替换为它们各自的具体值。
该示例关键代码:
(1)输入文档实体
public class Product {
   // 产品ID
   private String id;
   // 产品名称
   private String name;
   // 净价
   private double netPrice;
   // 单位
   private int spaceUnits;
   // 税率
   private double taxRate;
   // 折现率
   private double discountRate;
}(2)输出文档实体
public class Document {
   private String id;
   private String name;
   private double netPrice;
   private int spaceUnits;
   private double salesPrice;
}(3)投影操作关键代码
double shippingCosts = 1.2;
TypedAggregation<Product> agg = newAggregation(Product.class,
       project("name", "netPrice").andExpression(
   // [0] 表示引用 shippingCosts 参数
   "(netPrice * (1-discountRate)  + [0]) * (1+taxRate)", shippingCosts).as("salesPrice")
);
AggregationResults<Document> result = mongoTemplate.aggregate(agg, Document.class);
List<Document> resultList = result.getMappedResults();
for(Document doc : resultList) {
   System.out.println(JSONObject.toJSONString(doc));
}请注意,我们也可以在 Sp-EL 表达式中引用文档的其他字段。
(1)application.properties 配置
# Log logging.level.root=debug # MongoDB spring.data.mongodb.uri=mongodb://localhost:27017/test
(2)AppConfig.java 配置类
package com.hxstrive.springdata.mongodb.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
/**
* 配置 MongoTemplate
* @author hxstrive.com 2022/12/23
*/
@Slf4j
@Configuration
public class AppConfig {
   @Bean
   public MongoTemplate mongoTemplate(MongoDatabaseFactory mongoDatabaseFactory) {
       log.info("mongoTemplate({}, {})", mongoDatabaseFactory);
       return new MongoTemplate(mongoDatabaseFactory);
   }
}(3)输入文档实体
import lombok.Builder;
import lombok.Data;
/**
* 产品实体
* @author hxstrive.com
*/
@Data
@Builder
public class Product {
   // 产品ID
   private String id;
   // 产品名称
   private String name;
   // 净价
   private double netPrice;
   // 单位
   private int spaceUnits;
   // 税率
   private double taxRate;
   // 折现率
   private double discountRate;
}(4)输出文档实体
import lombok.Data;
/**
* 结果映射实体
* @author hxstrive.com
*/
@Data
public class Document {
   private String id;
   private String name;
   private double netPrice;
   private int spaceUnits;
   private double salesPrice;
}(5)客户端代码
import com.alibaba.fastjson.JSONObject;
import com.hxstrive.springdata.mongodb.entity.demo6.Document;
import com.hxstrive.springdata.mongodb.entity.demo6.Product;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import java.util.List;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.project;
/**
* 聚合框架示例6
* @author hxstrive.com
*/
@SpringBootTest
public class AggregationFrameworkDemo6 {
   @Autowired
   private MongoTemplate mongoTemplate;
   @BeforeEach
   public void init() {
       mongoTemplate.dropCollection(Product.class);
       // 准备数据
       mongoTemplate.insert(Product.builder().id("100").name("A").netPrice(100).spaceUnits(10)
               .discountRate(0.2).taxRate(0.1).build());
       mongoTemplate.insert(Product.builder().id("200").name("B").netPrice(200).spaceUnits(20)
               .discountRate(0.2).taxRate(0.1).build());
       mongoTemplate.insert(Product.builder().id("300").name("C").netPrice(300).spaceUnits(30)
               .discountRate(0.3).taxRate(0.1).build());
       mongoTemplate.insert(Product.builder().id("400").name("D").netPrice(400).spaceUnits(40)
               .discountRate(0.3).taxRate(0.1).build());
   }
   @Test
   public void contextLoads() {
       double shippingCosts = 1.2;
       TypedAggregation<Product> agg = newAggregation(Product.class,
               project("name", "netPrice").andExpression(
           // [0] 表示引用 shippingCosts 参数
           "(netPrice * (1-discountRate)  + [0]) * (1+taxRate)", shippingCosts).as("salesPrice")
       );
       AggregationResults<Document> result = mongoTemplate.aggregate(agg, Document.class);
       List<Document> resultList = result.getMappedResults();
       for(Document doc : resultList) {
           System.out.println(JSONObject.toJSONString(doc));
       }
       // 结果:
       // {"id":"100","name":"A","netPrice":100.0,"salesPrice":89.32000000000001,"spaceUnits":0}
       // {"id":"200","name":"B","netPrice":200.0,"salesPrice":177.32,"spaceUnits":0}
       // {"id":"300","name":"C","netPrice":300.0,"salesPrice":232.32,"spaceUnits":0}
       // {"id":"400","name":"D","netPrice":400.0,"salesPrice":309.32,"spaceUnits":0}
       // 执行的语句如下:
       // [{ "$project" : { "name" : 1, "netPrice" : 1,
       //    "salesPrice" : {
       //        "$multiply" : [
       //            { "$add" : [{ "$multiply" : ["$netPrice", {
       //                "$subtract" : [1, "$discountRate"]}]}, 1.2]},
       //            { "$add" : [1, "$taxRate"]}]}}
       // }]
   }
}
            