如何用Java Spring Boot执行文件中的MongoDB聚合查询并传参?
问题解答:MongoDB聚合查询文件化+Spring Boot执行及参数传递
完全可行,你可以将MongoDB聚合管道存储为JSON文件,在Spring Boot应用中读取并执行,同时也支持从Java端向查询传递参数。以下是具体实现方案和示例:
一、将聚合查询存储为JSON文件
把Mongo Shell中使用的聚合管道数组提取出来,保存为独立的JSON文件。比如你在Mongo Bash中执行的聚合查询:
db.orders.aggregate([ { $match: { status: "completed" } }, { $group: { _id: "$userId", totalSpent: { $sum: "$amount" } } } ])
将其中的管道数组保存为classpath:aggregations/order-stats-pipeline.json,内容如下:
[ { "$match": { "status": "completed" } }, { "$group": { "_id": "$userId", "totalSpent": { "$sum": "$amount" } } } ]
二、Spring Boot中读取文件并执行聚合
首先确保项目引入MongoDB依赖(pom.xml):
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency>
然后编写服务类,读取JSON文件并执行聚合:
import com.mongodb.client.result.AggregateIterable; import org.bson.Document; import org.springframework.core.io.ClassPathResource; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.stereotype.Service; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.util.List; @Service public class OrderAggregationService { private final MongoTemplate mongoTemplate; private final ObjectMapper objectMapper; // 构造注入Spring默认配置的Bean public OrderAggregationService(MongoTemplate mongoTemplate, ObjectMapper objectMapper) { this.mongoTemplate = mongoTemplate; this.objectMapper = objectMapper; } public AggregateIterable<Document> getCompletedOrderStats() throws IOException { // 读取classpath下的聚合管道文件 ClassPathResource resource = new ClassPathResource("aggregations/order-stats-pipeline.json"); // 解析JSON数组为MongoDB Document列表 List<Document> pipeline = objectMapper.readValue( resource.getInputStream(), new TypeReference<List<Document>>() {} ); // 执行聚合查询 return mongoTemplate.getCollection("orders").aggregate(pipeline); } }
三、向文件中的查询传递参数
有两种常用的参数传递方式,按需选择:
方式1:占位符替换(简单场景)
修改JSON文件,用自定义占位符标记参数位置,比如aggregations/order-stats-with-params.json:
[ { "$match": { "status": "{{status}}", "amount": { "$gte": {{minAmount}} } } }, { "$group": { "_id": "$userId", "totalSpent": { "$sum": "$amount" } } } ]
在服务类中读取文件字符串后替换占位符:
public AggregateIterable<Document> getOrderStatsByStatus(String status, int minAmount) throws IOException { ClassPathResource resource = new ClassPathResource("aggregations/order-stats-with-params.json"); // 读取文件为字符串 String pipelineJson = new String(resource.getInputStream().readAllBytes()); // 替换占位符(注意字符串参数要加引号) pipelineJson = pipelineJson.replace("{{status}}", "\"" + status + "\"") .replace("{{minAmount}}", String.valueOf(minAmount)); // 解析为管道列表并执行 List<Document> pipeline = objectMapper.readValue(pipelineJson, new TypeReference<List<Document>>() {}); return mongoTemplate.getCollection("orders").aggregate(pipeline); }
方式2:MongoDB原生变量(推荐,安全无注入风险)
利用MongoDB的变量机制,在管道中使用$$varName定义变量,执行时传入参数值。修改JSON文件aggregations/order-stats-with-mongo-vars.json:
[ { "$match": { "$expr": { "$and": [ { "$eq": ["$status", "$$targetStatus"] }, { "$gte": ["$amount", "$$minAmount"] } ] } } }, { "$group": { "_id": "$userId", "totalSpent": { "$sum": "$amount" } } } ]
服务类中执行时传入变量:
public AggregateIterable<Document> getOrderStatsWithMongoVars(String targetStatus, int minAmount) throws IOException { ClassPathResource resource = new ClassPathResource("aggregations/order-stats-with-mongo-vars.json"); List<Document> pipeline = objectMapper.readValue( resource.getInputStream(), new TypeReference<List<Document>>() {} ); // 构造变量文档 Document variables = new Document("targetStatus", targetStatus) .append("minAmount", minAmount); // 传入变量并执行聚合 return mongoTemplate.getCollection("orders") .aggregate(pipeline) .with(variables); }
注意事项
- 确保JSON文件格式严格符合MongoDB聚合语法,操作符前缀
$不能省略,键名必须用双引号。 - 复杂场景优先选择MongoDB原生变量方式,避免字符串替换带来的注入风险。
- JSON文件建议放在
src/main/resources目录下,便于Spring Boot自动读取。
内容的提问来源于stack exchange,提问作者trytocode
相关产品推荐
相关产品推荐

