MongoDB中如何更新嵌套数组内对象中的数组元素
问题排查与解决方案
核心问题分析
- 更新路径错误:
updateKey里写的CMA.userStocks...是错误的,MongoDB更新操作的路径需从文档根字段开始,正确路径应为userStocks.$[elem1].shares.$[elem2].amount,CMA是你查询到的文档变量,并非数据库字段名。 - 数组过滤器格式错误:
arrayFilters需要拆分为两个独立的过滤对象,分别对应外层数组的elem1和内层数组的elem2,不能将两个条件合并在同一个对象中。 - 操作逻辑冲突:你同时混用了“查询文档后修改保存”和
updateOne直接操作数据库两种方式,容易导致逻辑混乱,且updateOne无需依赖提前查询的CMA变量。 - 数据类型未处理:
args[1]若为字符串类型,会导致$inc操作失败,需先转为整数。
修正后的代码(保留原有逻辑框架)
for(var i = 0; i < CMA.userStocks.length; i++) { if(CMA.userStocks[i].name == data.userID) { for(var z = 0; z < CMA.userStocks[i].shares.length; z++) { if(CMA.userStocks[i].shares[z].companyName == args[0]) { // 修正更新路径与数组过滤器格式 Data.updateOne( { userID: 'CMA' }, { "$inc": { "userStocks.$[elem1].shares.$[elem2].amount": parseInt(args[1]) } }, { arrayFilters: [ { "elem1.name": data.userID }, { "elem2.companyName": args[0] } ] } ).then(() => { purchaseComplete(); }).catch(err => { console.log(err); }); return; } } // 新增shares元素并保存 CMA.userStocks[i].shares.push({ companyName: args[0], amount: parseInt(args[1]) }); CMA.save().then(() => { purchaseComplete(); }).catch(err => console.log(err)); return; } } // 新增userStocks元素并保存 CMA.userStocks.push({ name: data.userID, shares: [{ companyName: args[0], amount: parseInt(args[1]) }] }); CMA.save().then(() => { purchaseComplete(); }).catch(err => console.log(err)); purchaseComplete(); return;
更高效的原子更新方案(无需提前查询文档)
直接通过MongoDB原子操作完成“存在则更新,不存在则插入”的逻辑,减少数据库交互,避免并发修改问题:
const userId = 'CMA'; const targetUserName = data.userID; const companyName = args[0]; const amount = parseInt(args[1]); // 第一步:尝试更新已存在的amount Data.updateOne( { userID: userId }, { $inc: { "userStocks.$[elem1].shares.$[elem2].amount": amount } }, { arrayFilters: [ { "elem1.name": targetUserName }, { "elem2.companyName": companyName } ] } ).then(result => { if (result.modifiedCount === 0) { // 第二步:若shares不存在,往对应userStocks的shares中新增 return Data.updateOne( { userID: userId, "userStocks.name": targetUserName }, { $push: { "userStocks.$.shares": { companyName, amount } } } ); } return result; }).then(result => { if (result.modifiedCount === 0) { // 第三步:若userStocks也不存在,直接新增整个userStocks元素 return Data.updateOne( { userID: userId }, { $push: { userStocks: { name: targetUserName, shares: [{ companyName, amount }] } } } ); } return result; }).then(() => { purchaseComplete(); }).catch(err => { console.log(err); });
内容的提问来源于stack exchange,提问作者Gabrielnigme20
相关产品推荐
相关产品推荐

