如何在Mongoose中更新多条文档并返回更新后的文档数据
Mongoose批量更新后返回更新文档的实现方案
首先明确:MongoDB 原生的 updateMany 设计上就只会返回写入结果计数,不会返回实际文档内容,就算配置new: true也不会生效,这个参数仅对单条更新的findOneAndUpdate方法生效。
适配你的场景的实现代码
你的场景是每分钟执行一次,单次处理数千条数据,下面的方案性能足够,逻辑也简单,还支持事务保证数据一致性:
const checkAndUpdateSubscription = async () => { const session = await ModelModel.startSession(); try { // 开启事务避免中间其他操作修改数据导致结果不一致 session.startTransaction(); const filter = { "payments.0.stripeSubscriptionEndDate": { $lte: today }, hasPaid: true, }; const update = { $set: { hasPaid: false, isSubscriptionNew: 0 } }; // 第一步:查询所有符合条件的文档ID,仅查ID减少IO开销 const targetDocs = await ModelModel.find(filter, '_id', { session }).lean(); const targetIds = targetDocs.map(doc => doc._id); if (targetIds.length === 0) { await session.commitTransaction(); session.endSession(); return []; } // 第二步:批量更新匹配到的文档 await ModelModel.updateMany({ _id: { $in: targetIds } }, update, { session }); // 第三步:查询更新后的全量文档 const updatedDocs = await ModelModel.find({ _id: { $in: targetIds } }, null, { session }).lean(); // 提交事务 await session.commitTransaction(); session.endSession(); // 此处可直接调用外部服务传递更新后的文档 // sendUpdateModelToOutsideService(updatedDocs) return updatedDocs; } catch (error) { // 出错回滚事务 await session.abortTransaction(); session.endSession(); throw error; } };
注意事项
- 如果你不需要强一致性,也可以去掉事务逻辑,性能会更好,非核心业务场景下出错概率极低
- 单次处理数千条数据的情况下,这个方案的耗时基本在几十毫秒级别,完全满足每分钟执行的定时任务要求
- 如果后续数据量涨到十万级别,可以换成
bulkWrite配合批量单条更新的方式优化,当前量级不需要额外调整
备选方案(小数据量场景)
如果单次处理数据量在100条以内,也可以用遍历更新的方式,代码更简单:
const checkAndUpdateSubscription = async () => { const filter = { "payments.0.stripeSubscriptionEndDate": { $lte: today }, hasPaid: true, }; const updateFields = { hasPaid: false, isSubscriptionNew: 0 }; const targetDocs = await ModelModel.find(filter); const updatedDocs = await Promise.all(targetDocs.map(async doc => { Object.assign(doc, updateFields); await doc.save(); return doc; })); // sendUpdateModelToOutsideService(updatedDocs) return updatedDocs; };
该方案缺点是每次save都会触发一次数据库请求,数据量大的时候性能差,不适合你的数千条量级的场景。
内容的提问来源于stack exchange,提问作者intercoder
相关产品推荐
相关产品推荐

