MongoDB多文档批量更新插入场景下bulkWrite实现及性能问题咨询
问题分析与优化方案
现有实现的问题
你当前的代码存在两处核心问题:
- 逻辑错误:每个输入文档对应两个顺序执行的
updateOne操作,若匹配到已有文档,第一个操作先将count自增1,第二个操作直接把count重置为0,完全无法实现“匹配则自增count”的需求。 - 性能问题:你对每个输入文档都单独调用一次
bulkWrite,如果有1万条输入就要发起1万次数据库请求,网络IO开销、数据库连接开销都会非常高,处理5千~1万条数据会产生严重的性能浪费。
优化实现方案
你只需要用单次updateOne + upsert参数 + $setOnInsert运算符即可实现需求,且批量攒操作后统一调用bulkWrite,性能提升非常明显。
前置优化建议
建议先给process集合创建pId、apikey、primaryKey三个字段的联合唯一索引,既可以加速匹配查询,也能避免并发场景下插入重复数据:
db.collection("process").createIndex({ pId: 1, apikey: 1, primaryKey: 1 }, { unique: true })
优化后的代码
const ops = inputDocs.map(input => { const { pId, apikey, primaryKey } = input; return { updateOne: { filter: { pId, apikey, primaryKey }, update: { // 匹配到已有文档时生效:count自增1,更新更新时间 $inc: { count: 1 }, $set: { updatedAt: Date.now() }, // 仅插入新文档时生效:写入所有新文档字段,count初始为0,写入创建时间 $setOnInsert: { ...input, count: 0, createdAt: Date.now() } }, // 开启upsert,匹配不到则插入新文档 upsert: true } } }); // 统一执行批量操作,也可按每1000条拆分批次执行,避免单次请求体过大 await db.collection("process").bulkWrite(ops, { ordered: false });
说明:设置
ordered: false可以让批量操作并行执行,不会因为单条操作失败中断整个批量任务,性能比有序执行高30%以上,如果你的业务不需要保证操作顺序建议开启。
性能表现
优化后处理5千~1万条数据,仅需要发起1次(或少量批次)数据库请求,常规配置的MongoDB实例处理1万条批量操作的耗时基本在100ms以内,不会产生过高的性能开销。
内容的提问来源于stack exchange,提问作者abinas patra
相关产品推荐
相关产品推荐

