该示例演示了在投影操作中使用从 Sp-EL 表达式派生的简单算术运算。
Spring Expression Language (简称SpEL) 是一种功能强大的表达式语言,是 Spring 提供的,该语言类似于 JSP 当中的 EL 表达式。但提供了很多额外的功能,最出色的就是函数调用和简单字符串的模板函数。他需要使用 Spring 提供的解析器来解析,但是他不依赖于 Spring,可以独立使用。在 Spring 程序当中,我们不用管解析器,由 Spring 来帮我们自动构建。我们只需要写想要表达的字符串,交给 Spring 来进行解析即可。
示例关键代码如下:
(1)输入文档实体
public class Product { // 产品ID private String id; // 产品名称 private String name; // 净价 private double netPrice; // 单位 private int spaceUnits; }
(2)输出文档实体
public class Document { private String id; private String name; private double netPrice; private int spaceUnits; private double netPricePlus1; private double netPriceMinus1; private double grossPrice; private double netPriceDiv2; private int spaceUnitsMod2; private double grossPriceIncludingDiscountAndCharge; }
(3)投影操作关键代码
TypedAggregation<Product> agg = newAggregation(Product.class, project("name", "netPrice") // 加1 .andExpression("netPrice + 1").as("netPricePlus1") // 减1 .andExpression("netPrice - 1").as("netPriceMinus1") // 除2 .andExpression("netPrice / 2").as("netPriceDiv2") // 乘 1.19 .andExpression("netPrice * 1.19").as("grossPrice") // 取 2 的模 .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(); for(Document doc : resultList) { System.out.println(JSONObject.toJSONString(doc)); }
(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; }
(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 netPricePlus1; private double netPriceMinus1; private double grossPrice; private double netPriceDiv2; private int spaceUnitsMod2; private double grossPriceIncludingDiscountAndCharge; }
(5)客户端代码
import com.alibaba.fastjson.JSONObject; import com.hxstrive.springdata.mongodb.entity.demo5.Document; import com.hxstrive.springdata.mongodb.entity.demo5.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; /** * 聚合框架示例5 * @author hxstrive.com */ @SpringBootTest public class AggregationFrameworkDemo5 { @Autowired private MongoTemplate mongoTemplate; @BeforeEach public void init() { mongoTemplate.dropCollection(Product.class); // 准备数据 mongoTemplate.insert(Product.builder().id("100").name("A").netPrice(100).spaceUnits(10).build()); mongoTemplate.insert(Product.builder().id("200").name("B").netPrice(200).spaceUnits(20).build()); mongoTemplate.insert(Product.builder().id("300").name("C").netPrice(300).spaceUnits(30).build()); mongoTemplate.insert(Product.builder().id("400").name("D").netPrice(400).spaceUnits(40).build()); } @Test public void contextLoads() { TypedAggregation<Product> agg = newAggregation(Product.class, project("name", "netPrice") // 加1 .andExpression("netPrice + 1").as("netPricePlus1") // 减1 .andExpression("netPrice - 1").as("netPriceMinus1") // 除2 .andExpression("netPrice / 2").as("netPriceDiv2") // 乘 1.19 .andExpression("netPrice * 1.19").as("grossPrice") // 取 2 的模 .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(); for(Document doc : resultList) { System.out.println(JSONObject.toJSONString(doc)); } // 结果: // {"grossPrice":119.0,"grossPriceIncludingDiscountAndCharge":96.628,"id":"100","name":"A", // "netPrice":100.0,"netPriceDiv2":50.0,"netPriceMinus1":99.0,"netPricePlus1":101.0,"spaceUnits":0,"spaceUnitsMod2":0} // {"grossPrice":238.0,"grossPriceIncludingDiscountAndCharge":191.82799999999997,"id":"200", // "name":"B","netPrice":200.0,"netPriceDiv2":100.0,"netPriceMinus1":199.0,"netPricePlus1":201.0,"spaceUnits":0,"spaceUnitsMod2":0} // {"grossPrice":357.0,"grossPriceIncludingDiscountAndCharge":287.02799999999996,"id":"300","name":"C", // "netPrice":300.0,"netPriceDiv2":150.0,"netPriceMinus1":299.0,"netPricePlus1":301.0,"spaceUnits":0,"spaceUnitsMod2":0} // {"grossPrice":476.0,"grossPriceIncludingDiscountAndCharge":382.22799999999995,"id":"400","name":"D", // "netPrice":400.0,"netPriceDiv2":200.0,"netPriceMinus1":399.0,"netPricePlus1":401.0,"spaceUnits":0,"spaceUnitsMod2":0} // 执行的语句如下: // [{ "$project" : { "name" : 1, "netPrice" : 1, // "netPricePlus1" : { "$add" : ["$netPrice", 1]}, // "netPriceMinus1" : { "$subtract" : ["$netPrice", 1]}, // "netPriceDiv2" : { "$divide" : ["$netPrice", 2]}, // "grossPrice" : { "$multiply" : ["$netPrice", 1.19]}, // "spaceUnitsMod2" : { "$mod" : ["$spaceUnits", 2]}, // "grossPriceIncludingDiscountAndCharge" : { // "$multiply" : [{ "$add" : [{ "$multiply" : ["$netPrice", 0.8]}, 1.2]}, 1.19]} // }}] } }