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

MongoDB按name和user字段删除重复文档保留单条实现方法

MongoDB 重复文档删除方案(按name+user字段去重保留单条)

前置提醒

  • 所有生产环境操作前必须全量备份目标集合,避免误操作导致数据丢失
  • 若集合数据量超过10万,优先选择分批删除方案,避免聚合操作占用过多内存或长时间锁库

方案1:聚合管道直接批量删除(适配MongoDB 4.2及以上版本,中小数据量集合首选)

核心逻辑是按name+user字段分组,每组保留1条文档,删除其余重复项,直接在聚合管道内完成删除操作:

// 把下面的「你的集合名」替换成实际要操作的集合名称
db.你的集合名.aggregate([
  // 按重复判定规则分组
  {
    $group: {
      _id: { name: "$name", user: "$user" },
      keepDocId: { $first: "$_id" }, // 每组取第一条作为保留文档,要保留最新插入的文档就把$first换成$last
      allDocIds: { $push: "$_id" }
    }
  },
  // 过滤掉没有重复的分组(仅1条文档不需要处理)
  {
    $match: {
      $expr: { $gt: [{ $size: "$allDocIds" }, 1] }
    }
  },
  // 筛选出每组需要删除的文档ID:排除要保留的ID即可
  {
    $project: {
      deleteIds: {
        $filter: {
          input: "$allDocIds",
          cond: { $ne: ["$$this", "$keepDocId"] }
        }
      }
    }
  },
  // 直接匹配ID执行删除
  {
    $merge: {
      into: "你的集合名",
      on: "_id",
      whenMatched: "delete",
      whenNotMatched: "discard"
    }
  }
], { allowDiskUse: true }) // 开启磁盘临时存储,避免大数据量下触发16M内存聚合限制

方案2:分批删除脚本(适配所有MongoDB版本,大数据量集合首选)

如果你的集合文档量在百万级以上,用下面的mongo shell脚本分批处理,不会长时间占用库锁,对线上业务影响更小:

// 替换为实际集合名
const COLLECTION_NAME = "你的集合名";
// 单批删除的文档数,根据服务器性能调整,建议1000-10000区间
const BATCH_SIZE = 1000;
let totalDeleted = 0;

while (true) {
  // 每次取一组重复数据处理
  const duplicateGroup = db[COLLECTION_NAME].aggregate([
    {
      $group: {
        _id: { name: "$name", user: "$user" },
        keepDocId: { $first: "$_id" },
        allDocIds: { $push: "$_id" }
      }
    },
    { $match: { $expr: { $gt: [{ $size: "$allDocIds" }, 1] } } },
    { $limit: 1 },
    {
      $project: {
        deleteIds: {
          $filter: {
            input: "$allDocIds",
            cond: { $ne: ["$$this", "$keepDocId"] }
          }
        }
      }
    }
  ]).toArray();

  // 没有找到重复数据就退出循环
  if (duplicateGroup.length === 0) break;

  const deleteIds = duplicateGroup[0].deleteIds;
  // 分批删除当前组的重复文档
  for (let i = 0; i < deleteIds.length; i += BATCH_SIZE) {
    const currentBatch = deleteIds.slice(i, i + BATCH_SIZE);
    const deleteRes = db[COLLECTION_NAME].deleteMany({ _id: { $in: currentBatch } });
    totalDeleted += deleteRes.deletedCount;
    print(`当前累计删除重复文档:${totalDeleted} 条`);
  }
}
print(`去重操作完成,共删除重复文档:${totalDeleted} 条`);

结果验证&后续优化

  • 执行完删除操作后,运行下面的聚合语句校验是否还有残留重复项,返回结果为空即表示去重完成:
db.你的集合名.aggregate([
  {
    $group: {
      _id: { name: "$name", user: "$user" },
      docCount: { $sum: 1 }
    }
  },
  { $match: { docCount: { $gt: 1 } } }
])
  • 去重完成后建议给name和user字段建联合唯一索引,从根源避免后续再产生重复数据:
db.你的集合名.createIndex({ name: 1, user: 1 }, { unique: true })

内容的提问来源于stack exchange,提问作者Filip

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 03:45:48