MongoDB多分组求和聚合查询转Spring MongoTemplate实现求助
解决方案:将MongoDB聚合查询转换为Spring MongoTemplate实现
原查询逻辑回顾
你的聚合查询核心是:关联集合B后,按集合A的_id分组,对比集合A中notes数组长度与关联的集合B文档数量,筛选不匹配的结果并按更新时间排序。
分步实现Spring MongoTemplate代码
1. 定义结果接收DTO(可选但推荐)
创建DTO类接收聚合结果,避免使用松散的Map结构:
import org.bson.types.ObjectId; import java.util.Date; public class CollectionAMismatchResult { private ObjectId _id; private int fromB; private int numberOfNotes; private Date updatedAt; // 构造器、getter、setter public CollectionAMismatchResult(ObjectId _id, int fromB, int numberOfNotes, Date updatedAt) { this._id = _id; this.fromB = fromB; this.numberOfNotes = numberOfNotes; this.updatedAt = updatedAt; } // 省略getter和setter方法 }
2. 构建完整聚合操作链
import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.aggregation.*; import org.springframework.data.mongodb.core.query.Criteria; import java.util.List; // 注入MongoTemplate实例 private final MongoTemplate mongoTemplate; public List<CollectionAMismatchResult> findMismatchedDocuments() { // 1. 实现$lookup:关联collectionB LookupOperation lookupOperation = Aggregation.lookup( "collectionB", // 目标集合名 "_id", // 集合A的关联字段 "idNotes", // 集合B的关联字段 "documentB" // 关联结果的别名 ); // 2. 实现$group:按_id分组,计算两个长度值并保留updatedAt GroupOperation groupOperation = Aggregation.group("_id") // 计算fromB:documentB数组长度,非数组则取0 .sum((context) -> new org.bson.Document("$cond", new org.bson.Document("if", new org.bson.Document("$isArray", "$documentB")) .append("then", new org.bson.Document("$size", "$documentB")) .append("else", 0) )).as("fromB") // 计算numberOfNotes:notes数组长度,非数组则取0 .sum((context) -> new org.bson.Document("$cond", new org.bson.Document("if", new org.bson.Document("$isArray", "$notes")) .append("then", new org.bson.Document("$size", "$notes")) .append("else", 0) )).as("numberOfNotes") // 保留分组内第一个updatedAt值 .first("updatedAt").as("updatedAt"); // 3. 实现$match:筛选长度不匹配的文档 MatchOperation matchOperation = Aggregation.match( Criteria.where("").expr( ComparisonOperators.Ne.valueOf("fromB").notEqualToValue("numberOfNotes") ) ); // 4. 实现$sort:按updatedAt降序排序 SortOperation sortOperation = Aggregation.sort(Sort.Direction.DESC, "updatedAt"); // 组装聚合管道 Aggregation aggregation = Aggregation.newAggregation( lookupOperation, groupOperation, matchOperation, sortOperation ); // 执行查询并转换为DTO列表 AggregationResults<CollectionAMismatchResult> results = mongoTemplate.aggregate( aggregation, "collectionA", CollectionAMismatchResult.class ); return results.getMappedResults(); }
关键细节说明
- GroupOperation复杂表达式:通过Lambda形式的
AggregationExpression手动构建MongoDB的$cond逻辑,解决Spring Data API无法直接覆盖复杂条件的问题。 - MatchOperation字段对比:使用
Criteria.where("").expr()实现MongoDB的$expr语法,支持对聚合计算后的字段进行对比。 - 类型安全处理:用DTO接收结果比直接使用Map更易维护,Spring会自动完成字段映射。
内容的提问来源于stack exchange,提问作者Barbi
相关产品推荐
相关产品推荐

