如何在Spring Boot中使用MongoTemplate实现MongoDB聚合查询?
在Spring Boot中用MongoTemplate实现MongoDB聚合筛选嵌套数组的正确方式
你的问题核心在于普通查询无法过滤嵌套数组中的元素,而且原代码的正则匹配逻辑和Mongo Shell中的操作不一致,再加上实体类映射可能不匹配,导致了空指针异常。下面一步步帮你解决:
为什么原代码不生效?
- 普通Query的局限性:你用
Criteria.where("listItems.item").regex(...)会返回整个包含符合条件元素的文档,但不会过滤数组里的其他不匹配元素——这和你在Mongo Shell中用$filter实现的数组筛选逻辑完全不同。 - 正则匹配逻辑错误:原代码里的
^" + item + "$"是精确匹配(要求字符串完全等于item),但你需要的是包含匹配(对应Mongo Shell里的/ja/i),这也是结果不符合预期的原因。 - 实体类映射问题:你返回的是
ListValue.class,但你的集合是qualification,文档结构包含code、description等顶级字段,这会导致MongoTemplate无法正确映射文档,返回null后触发空指针异常。
正确的聚合实现步骤
1. 定义匹配文档结构的实体类
首先要创建对应qualification集合的实体类,包含嵌套的listItems子对象:
import lombok.Data; import org.springframework.data.mongodb.core.mapping.Document; import java.util.List; @Document(collection = "qualification") @Data public class Qualification { private String code; private String description; private String status; private List<ListItem> listItems; private String returncode; private String message; @Data public static class ListItem { private String itemId; private String item; } }
2. 用MongoTemplate实现聚合查询
对应你在Mongo Shell中写的$match + $project聚合管道,用Spring Data的AggregationAPI来实现:
import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.aggregation.Aggregation; import org.springframework.data.mongodb.core.aggregation.ArrayOperators; import org.springframework.data.mongodb.core.aggregation.MatchOperation; import org.springframework.data.mongodb.core.aggregation.ProjectionOperation; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.stereotype.Repository; @Repository public class QualificationRepository { private final MongoTemplate mongoTemplate; // 构造注入MongoTemplate public QualificationRepository(MongoTemplate mongoTemplate) { this.mongoTemplate = mongoTemplate; } public Qualification getFilteredQualification(String code, String itemPattern) { // 1. 构建$match阶段:筛选code匹配的文档 MatchOperation matchStage = Aggregation.match(Criteria.where("code").is(code)); // 2. 构建$project阶段:用$filter筛选listItems数组,只保留item匹配正则的元素 ProjectionOperation projectStage = Aggregation.project("code", "description", "status", "returncode", "message") .and(ArrayOperators.Filter.filter("listItems") .as("listItem") .by(Criteria.where("listItem.item").regex(itemPattern, "i").getCriteriaObject())) .as("listItems"); // 组装聚合管道 Aggregation aggregation = Aggregation.newAggregation(matchStage, projectStage); // 执行聚合,返回唯一结果(假设code是唯一标识) return mongoTemplate.aggregate(aggregation, "qualification", Qualification.class).getUniqueMappedResult(); } }
3. 调用时避免空指针
当没有匹配到任何文档时,getUniqueMappedResult()会返回null,所以调用时一定要做非空判断:
// 示例调用 Qualification result = qualificationRepository.getFilteredQualification("DEVELOPER", "ja"); if (result != null) { // 处理筛选后的结果 System.out.println(result.getListItems()); // 只会包含Java和Javascript的条目 } else { // 处理未找到数据的情况 System.out.println("No matching qualification found"); }
关键细节说明
- 正则匹配:这里直接传入
itemPattern(比如"ja"),对应Mongo Shell里的/ja/i,实现忽略大小写的包含匹配。如果需要精确匹配,再加上^和$。 - 聚合结果映射:
aggregate()方法会将聚合后的文档正确映射到Qualification实体类,解决了原代码中实体类不匹配的问题。 - 空指针预防:通过非空判断避免返回null时触发的空指针异常,同时也能优雅处理无数据的场景。
内容的提问来源于stack exchange,提问作者M N
相关产品推荐
相关产品推荐

