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

MongoDB+Node.js高效批量插入百万用户通知记录最佳实践

MongoDB + Node.js 批量生成100万条用户通知最佳实践

针对100万存量用户批量生成对应通知的需求,优先选择MongoDB原生聚合管道写入方案,不需要手动遍历用户做逐次插入,全程在数据库层完成运算和写入,性能最高;如果通知内容需要经过Node.js层做复杂逻辑处理,再用游标分批读取+批量插入的方案即可。

方案一:数据库原生聚合写入(性能最优,优先推荐)

MongoDB 4.2及以上版本支持聚合管道$merge阶段,可以直接从源集合读取数据,加工成目标结构后直接写入目标集合,全程不需要把数据传输到应用层,没有网络IO开销,100万条数据通常几秒到十几秒就能跑完,是这类批量生成场景的最优解。

实现代码(Node.js驱动)

const { MongoClient } = require('mongodb');
async function batchCreateNotifications() {
  const client = new MongoClient('你的MongoDB连接地址');
  await client.connect();
  const db = client.db('你的业务库名');
  const usersCollection = db.collection('Users');

  await usersCollection.aggregate([
    // 把用户文档转换成通知结构
    {
      $project: {
        userID: "$_id", // 关联用户ID
        data: { $literal: "test data" }, // 固定通知内容,可替换为聚合支持的动态计算逻辑
        isSeen: { $literal: false },
        _id: 0 // 必须设为0,让MongoDB为通知自动生成新的主键ObjectId,避免主键冲突
      }
    },
    // 把生成的通知文档写入Notifications集合
    {
      $merge: {
        into: "Notifications",
        on: "_id",
        whenMatched: "keepExisting", // 重复执行任务时不覆盖已存在的通知
        whenNotMatched: "insert"
      }
    }
  ]).toArray(); // 触发聚合任务执行

  await client.close();
}
batchCreateNotifications();

注意事项

  • 执行前建议在业务低峰期操作,避免占用过多数据库IO影响线上业务
  • 任务执行完成后,可以给Notifications集合的userID字段建普通索引,后续查询用户通知效率更高

方案二:Node.js层分批处理(适合需要自定义复杂逻辑的场景)

如果通知内容需要调用外部服务、或者有复杂的业务逻辑必须在Node.js层计算生成,不要全量拉取所有用户到内存,也不要单条循环插入,采用游标分批读取+批量插入的模式实现,平衡内存占用和写入性能。

实现代码(Node.js驱动)

const { MongoClient } = require('mongodb');
async function batchCreateNotificationsWithLogic() {
  const client = new MongoClient('你的MongoDB连接地址');
  await client.connect();
  const db = client.db('你的业务库名');
  const usersCollection = db.collection('Users');
  const notifCollection = db.collection('Notifications');

  const BATCH_SIZE = 2000; // 单批处理条数,建议1000-5000之间,根据服务和DB性能调整
  let pendingBatch = [];
  // 用游标逐批拉取用户,不会全量加载到内存
  const userCursor = usersCollection.find({}, { projection: { _id: 1 } }).batchSize(BATCH_SIZE);

  for await (const user of userCursor) {
    // 此处可写自定义业务逻辑,生成对应通知内容
    const notification = {
      userID: user._id,
      data: "test data",
      isSeen: false
    };
    pendingBatch.push(notification);

    // 凑够一批就批量写入
    if (pendingBatch.length >= BATCH_SIZE) {
      await notifCollection.insertMany(pendingBatch, {
        ordered: false // 无序写入,跳过错误继续执行,写入性能更高
      });
      pendingBatch = [];
    }
  }

  // 写入最后不足一批的剩余数据
  if (pendingBatch.length > 0) {
    await notifCollection.insertMany(pendingBatch, { ordered: false });
  }

  await client.close();
}
batchCreateNotificationsWithLogic();

避坑提醒

  • 禁止全量拉取用户:不要写const allUsers = await usersCol.find({}).toArray()这类代码,100万条BSON文档加载到内存至少占数百MB,很容易触发Node.js进程OOM崩溃
  • 禁止单条循环插入:逐次调用insertOne会产生大量网络往返开销,写入效率比批量插入低两个量级,100万条数据可能跑数小时都无法完成
  • 单批大小不要超过5000:单批数据量过大会触发MongoDB单请求16MB大小限制,还会造成数据库瞬时IO压力过高
  • 副本集环境可临时调整写入配置:批量写入时可以临时把writeConcern设为w:1,不需要等待从节点确认写入,速度可提升30%以上,任务完成后改回原有配置即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 18:39:55