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