如何在MongoDB中借助另一集合字段批量更新多文档字段值?
MongoDB跨集合更新字段问题解决
问题场景
需要借助Col2集合的字段值更新Col1集合的对应字段:
- Col1初始数据:
{ field1: 1 }, { field1: 2 }, { field1: 1 }
- Col2数据:
{ field1: 1, field2: 234 }, { field1: 2, field2: 545 }, { field1: 1, field2: 234 }
匹配规则:当Col1的field1与Col2的field1相等时,将Col1的field1替换为Col2对应的field2值,期望Col1最终结果:
{ field1: 234 }, { field1: 545 }, { field1: 234 }
遇到的问题
自行编写的forEach脚本仅更新了第一个文档,脚本如下:
db.col1.find().forEach( function(doc1) { if(doc1.field1){ var doc2 = dB.col2.findOne({"field1": doc1.field1}); if(doc2) { doc1.field1 = doc2.field2; dB.col1.save(doc1); } } });
问题原因
脚本中存在拼写错误:MongoDB的全局数据库对象是小写的db,但你写成了dB。这个错误会导致脚本执行时抛出未定义变量的异常,中断后续循环,因此只更新了第一个文档。
解决方案
方案1:修正脚本拼写错误
将所有dB改为db即可正常执行:
db.col1.find().forEach( function(doc1) { if(doc1.field1){ var doc2 = db.col2.findOne({"field1": doc1.field1}); if(doc2) { doc1.field1 = doc2.field2; db.col1.save(doc1); } } });
方案2:更高效的批量更新(推荐)
对于大数据量,循环遍历的性能较差,推荐使用MongoDB的聚合管道结合更新操作:
MongoDB 4.2+版本(支持管道更新)
直接用updateMany配合管道完成跨集合匹配与更新:
db.col1.updateMany( {}, [ { $lookup: { from: "col2", localField: "field1", foreignField: "field1", as: "matches" } }, { $set: { field1: { $arrayElemAt: ["$matches.field2", 0] } } } ] );
低版本MongoDB
先通过聚合获取匹配关系,再批量更新:
db.col1.aggregate([ { $lookup: { from: "col2", localField: "field1", foreignField: "field1", as: "matchedDocs" } }, { $match: { matchedDocs: { $ne: [] } } }, { $addFields: { newField1: { $arrayElemAt: ["$matchedDocs.field2", 0] } } }, { $project: { _id: 1, newField1: 1 } } ]).forEach(function(doc) { db.col1.updateOne( { _id: doc._id }, { $set: { field1: doc.newField1 } } ); });
内容的提问来源于stack exchange,提问作者muni
相关产品推荐
相关产品推荐

