该示例演示了在投影操作中使用从 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"]}]}} // }] } }