You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 03:01:00