MongoDB NodeJS中第二个更新查询返回null的问题排查
问题分析与解决方案
问题根源
你遇到的核心问题是:更新side1后,内存中的flashcardObj还是原始旧数据,但数据库里的deck文档中对应flashcard的side1已经被修改。处理side2更新时,用旧的flashcardObj去匹配数据库里已更新的deck文档,因字段值不一致(side1已变更)导致匹配失败,findOneAndUpdate返回null。
单独更新side2时,数据库里的flashcard未被修改,flashcardObj与数据库值一致,所以能匹配成功。
解决方案
最可靠的方式是通过flashcard的_id定位deck数组中的元素,而非用整个对象匹配。MongoDB支持通过数组元素的字段精准定位,只要_id正确,就能无视其他字段变化找到目标元素。
修改flashcardDeck.findOneAndUpdate的查询条件,将flashcards: flashcardObj替换为"flashcards._id": flashcardID即可。
修改后的代码
for (let i = 0; i < currentFlashcardsArr.length; i++) { if (currentFlashcardsArr[i] !== newFlashcardsArr[i]) { console.log(i); const j = Math.floor(i / 2); const flashcardID = deck.flashcards[j]._id; if ((i % 2 === 0)) { console.log('side 1 updated'); // 更新独立的flashcard文档 await flashcard.findOneAndUpdate({ _id: flashcardID, deckId: deck._id }, { $set: { side1: newFlashcardsArr[i] } }); // 通过flashcard的_id定位deck中的数组元素 let promise1 = flashcardDeck.findOneAndUpdate( { _id: deck._id, "flashcards._id": flashcardID }, { $set: { 'flashcards.$.side1': newFlashcardsArr[i] } } ); let result = await Promise.all([promise1]); console.log(result); } if (i % 2 === 1) { console.log('side 2 updated'); await flashcard.findOneAndUpdate({ _id: flashcardID, deckId: deck._id }, { $set: { side2: newFlashcardsArr[i] } }); let promise2 = flashcardDeck.findOneAndUpdate( { _id: deck._id, "flashcards._id": flashcardID }, { $set: { 'flashcards.$.side2': newFlashcardsArr[i] } } ); let result = await Promise.all([promise2]); console.log(result); } } }
额外优化建议
- 可将重复的更新逻辑抽成独立函数,减少代码冗余;
- 若批量更新数量较多,建议合并数据库操作,降低IO次数提升性能。
内容的提问来源于stack exchange,提问作者Zsombor
相关产品推荐
相关产品推荐

