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

求助:如何用Node.js结合MongoDB基于多字段删除重复文档

多字段去重需求

我尝试用MongoDB聚合去重多次失败,转而用Node.js完成去重任务,目前已经实现了基于单个字段删除重复文档,但因为缺乏Node.js经验,无法完成基于多个字段的重复文档删除,希望能修改代码支持多字段去重。

现有代码

index.js

const MongoClient = require("mongodb").MongoClient;
require("dotenv").config();

async function removeDups() {
  try {
    const client = await MongoClient.connect(process.env.DB_URL, {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    });
    const DB = client.db(process.env.DB_NAME);
    const coll = DB.collection(process.env.COLL_NAME);
    const tempColl = DB.collection(process.env.TEMP_COLL_NAME);
    await tempColl.createIndex({ [process.env.UNIQUE_FIELD]: 1 }, { unique: true });
    const data = coll.find();
    const total = await data.count();
    let count = 0;
    let dupCount = 0;
    data.forEach(async (item) => {
      try {
        await tempColl.insertOne({ ...item });
        count++;
        console.log("成功复制 " + count + " 条唯一文档。");
      } catch (error) {
        // 捕获重复错误并忽略,其他错误抛出
        dupCount++;
      }
      if (count + dupCount == total) {
        console.log("已插入 " + count + " 条唯一文档,移除了 " + dupCount + " 条重复文档。");
        await DB.renameCollection(process.env.COLL_NAME,"temp_collection_review")
        await DB.renameCollection(process.env.TEMP_COLL_NAME,process.env.COLL_NAME)
        client.close();
        process.exit(1);
      }
    });
  } catch (error) {
    console.log(error);
  }
}

removeDups();

.env

DB_URL = "mongodb://127.0.0.1:27017"
DB_NAME = test
COLL_NAME = test
UNIQUE_FIELD = user
TEMP_COLL_NAME = products_temp

修改方案(支持多字段去重)

1. 更新 .env 配置

将单个字段配置改为逗号分隔的多字段列表,示例如下:

# 示例:以user和email两个字段的组合作为去重依据
UNIQUE_FIELDS = user,email
DB_URL = "mongodb://127.0.0.1:27017"
DB_NAME = test
COLL_NAME = test
TEMP_COLL_NAME = products_temp

2. 修改 index.js 代码

调整索引创建逻辑为复合唯一索引,同时修复原代码的异步遍历问题:

const MongoClient = require("mongodb").MongoClient;
require("dotenv").config();

async function removeDups() {
  try {
    const client = await MongoClient.connect(process.env.DB_URL, {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    });
    const DB = client.db(process.env.DB_NAME);
    const coll = DB.collection(process.env.COLL_NAME);
    const tempColl = DB.collection(process.env.TEMP_COLL_NAME);

    // 将逗号分隔的字段字符串转为复合索引对象
    const uniqueFields = process.env.UNIQUE_FIELDS.split(',').reduce((indexObj, field) => {
      indexObj[field.trim()] = 1;
      return indexObj;
    }, {});
    // 创建复合唯一索引,MongoDB会根据字段组合判断重复
    await tempColl.createIndex(uniqueFields, { unique: true });

    const data = coll.find();
    const total = await data.count();
    let count = 0;
    let dupCount = 0;

    // 改用for await...of遍历,解决forEach异步导致的计数不准确问题
    for await (const item of data) {
      try {
        await tempColl.insertOne({ ...item });
        count++;
        console.log("成功复制 " + count + " 条唯一文档。");
      } catch (error) {
        // 仅忽略重复键错误(错误码11000),其他错误正常抛出
        if (error.code === 11000) {
          dupCount++;
        } else {
          throw error;
        }
      }
    }

    console.log("已插入 " + count + " 条唯一文档,移除了 " + dupCount + " 条重复文档。");
    await DB.renameCollection(process.env.COLL_NAME, "temp_collection_review");
    await DB.renameCollection(process.env.TEMP_COLL_NAME, process.env.COLL_NAME);
    client.close();
    process.exit(0);

  } catch (error) {
    console.error("执行出错:", error);
    process.exit(1);
  }
}

removeDups();

关键修改说明

  • 替换单字段配置UNIQUE_FIELD为多字段配置UNIQUE_FIELDS,支持逗号分隔多个字段
  • 创建复合唯一索引,MongoDB会基于多个字段的组合判断文档是否重复
  • 用for await...of替换forEach,解决原代码异步遍历导致的计数、流程判断不准确问题
  • 增加错误类型判断,仅忽略重复键错误,其他错误正常抛出,便于排查问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 21:15:36