You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB嵌套数组更新失败求助:如何更新数组内的数组?

问题分析与修复方案:MongoDB嵌套数组更新失效

你的代码在新增用户-主题-子主题的测试记录时正常,但更新已有组合的scores数组时失效,问题完全出在if(existingTopicSubtopic)代码段里,核心是对MongoDB数组更新操作符的用法理解有误:

错误点拆解

  1. 你试图用$addToSet往testRecords数组里插入新对象,但实际需求是更新已有testRecord项里的scores子数组,而非新增testRecord条目
  2. scores.$的用法错误,位置操作符$已经能定位到匹配topic和subtopic的testRecords元素,不需要把整个scores对象嵌套在testRecords数组的新元素里

修复后的核心代码

把if分支里的更新逻辑替换为:

if(existingTopicSubtopic) {
    console.log('已有该主题-子主题记录,更新scores')
    user = await User.findOneAndUpdate(
        {
            _id: userId,
            'testRecords.topic': topicName,
            'testRecords.subtopic': subtopicName
        },
        { 
            // 用$push直接往匹配到的testRecords项的scores数组里加新分数
            // 如果要避免重复的分数记录,把$push换成$addToSet即可
            $push: {
                'testRecords.$.scores': {
                    rightAnswers,
                    wrongAnswers,
                    date
                }
            }
        },
        // 可选:返回更新后的文档,方便验证或返回给前端
        { new: true }
    )
}

完整修复后的函数

exports.updateUserTestRecord = async (req, res) => {
    console.log('req.body', req.body)
    const { topicName, subtopicName, rightAnswers, wrongAnswers, date } = req.body;

    const { userId } = jwt.verify(req.headers.authorization, process.env.JWT_SECRET);

    const existingTopicSubtopic = await User.findOne(
        {
            _id: userId,
            'testRecords.topic': topicName,
            'testRecords.subtopic': subtopicName
        }
    )

    let user;

    if(existingTopicSubtopic) {
        console.log('已有该主题-子主题记录,更新scores')
        user = await User.findOneAndUpdate(
            {
                _id: userId,
                'testRecords.topic': topicName,
                'testRecords.subtopic': subtopicName
            },
            { 
                $push: {
                    'testRecords.$.scores': {
                        rightAnswers,
                        wrongAnswers,
                        date
                    }
                }
            },
            { new: true }
        )
    } else {
        console.log('无该主题-子主题记录,新增测试记录')
        user = await User.findOneAndUpdate(
            { _id: userId },
            { 
                $addToSet: { 
                    testRecords: [
                        {
                            topic: topicName,
                            subtopic: subtopicName,
                            scores: [
                                { 
                                    rightAnswers,
                                    wrongAnswers,
                                    date,
                                }
                            ]
                        }
                    ] 
                } 
            },
            { new: true }
        )
    }
    // 给客户端返回响应
    res.status(200).json({ user })
}

补充说明

  • $位置操作符会自动匹配查询条件中第一个符合的testRecords元素,刚好对应你要更新的目标记录
  • 如果需要确保scores数组无重复(比如同一天的分数不重复),将$push替换为$addToSet即可,MongoDB会自动跳过重复对象
  • { new: true }选项让findOneAndUpdate返回更新后的文档,方便验证结果或返回给前端

内容的提问来源于stack exchange,提问作者koque

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 19:40:34