MongoDB分组跳过每组首条记录的实现及Spring Data集成方案
问题解答
1. 可通过单条MongoDB聚合查询实现
完全可以,以下是对应的聚合管道语句:
db.employee.aggregate([ // 先按部门升序、姓名降序排序 { $sort: { department: 1, name: -1 } }, // 按部门分组,将同部门员工按排序顺序存入数组 { $group: { _id: "$department", employees: { $push: "$$ROOT" } } }, // 跳过每组首条记录(姓名降序的第一个) { $project: { employees: { $slice: ["$employees", 1, { $size: "$employees" }] } } }, // 将数组展开为单个文档 { $unwind: "$employees" }, // 还原为原始文档结构 { $replaceRoot: { newRoot: "$employees" } } ])
说明:
$sort确保同部门内员工按name降序排列$group收集同部门所有员工到数组中$slice参数1表示从索引1开始(跳过第一个元素),$size确保取到剩余全部元素$unwind和$replaceRoot将数组还原为单个文档格式
2. Spring Data Aggregation实现方式
使用Spring Data MongoDB的Aggregation API对应实现上述逻辑:
import org.springframework.data.mongodb.core.aggregation.*; import org.springframework.data.domain.Sort; import java.util.List; // 构建聚合操作步骤 SortOperation sortStep = Aggregation.sort(Sort.Direction.ASC, "department") .and(Sort.Direction.DESC, "name"); GroupOperation groupStep = Aggregation.group("department") .push("$$ROOT").as("employees"); ProjectionOperation sliceStep = Aggregation.project() .and(Aggregation.slice("employees", 1, Aggregation.size("employees"))).as("employees"); UnwindOperation unwindStep = Aggregation.unwind("employees"); ReplaceRootOperation replaceRootStep = Aggregation.replaceRoot("employees"); // 组装完整聚合管道 Aggregation aggregation = Aggregation.newAggregation( sortStep, groupStep, sliceStep, unwindStep, replaceRootStep ); // 执行聚合查询 AggregationResults<Employee> results = mongoTemplate.aggregate(aggregation, "employee", Employee.class); List<Employee> targetEmployees = results.getMappedResults();
3. 适配mongoTemplate.findAllAndRemove()删除匹配文档
findAllAndRemove()需接收Query对象,可先通过聚合获取目标文档的_id集合,再构建删除查询:
import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Criteria; import java.util.List; import java.util.stream.Collectors; // 第一步:聚合查询仅获取目标文档的_id ProjectionOperation projectIdStep = Aggregation.project() .and(Aggregation.slice("employees", 1, Aggregation.size("employees"))).as("employees"); UnwindOperation unwindIdStep = Aggregation.unwind("employees"); ProjectionOperation extractIdStep = Aggregation.project("employees._id").as("_id"); Aggregation idAggregation = Aggregation.newAggregation( sortStep, groupStep, projectIdStep, unwindIdStep, extractIdStep ); AggregationResults<org.bson.Document> idResults = mongoTemplate.aggregate(idAggregation, "employee", org.bson.Document.class); List<Object> targetIds = idResults.getMappedResults().stream() .map(doc -> doc.get("_id")) .collect(Collectors.toList()); // 第二步:构建查询并执行删除 Query deleteQuery = new Query(Criteria.where("_id").in(targetIds)); List<Employee> deletedEmployees = mongoTemplate.findAllAndRemove(deleteQuery, Employee.class);
内容的提问来源于stack exchange,提问作者Kartik Gautam
相关产品推荐
相关产品推荐

