首页 > 解决方案 > 在 MongoDB 中保存数组字段

问题描述

伙计们-我正在尝试在 MongoDB 中保存一个数组字段,但它不想正确保存。

我正在尝试构建一个琐事托管应用程序。有问题的 API 端点将允许主机获取在一轮中为每个问题收到的每个响应,并确定它是否应该获得全部积分、没有积分或介于两者之间。我的圆形文档如下所示:

{
    "_id":{"$oid":"6067c6c7c1821e3db0530eb9"},
    "type":"general",
    "game ":{"$oid":"6067c666c1821e3db0530eb7"},
    "questions":[
        {
            "text":"What is the capital of Finland?",
            "answer":"Helsinki",
            "value":2,
            "key":[],
            "number":1
        },
        {
            "text":"What is the capital of Kazakhstan?",
            "answer":"Nursultan",
            "value":2,
            "key":[],
            "number":2
        }
    ],
    "title":"My test round",
    "description":"This describes my test round.",
    "settings":{
        "endBonus":false,
        "maxWager":0,
        "releaseQuestions":false,
        "answerAfterEach":false
    },
    "owner":{"$oid":"605271517fce7249cc8eb436"},
    "__v":3
}

req.body 看起来像这样:

{
    "key": [
        {
            "answer":"Helsinki",
            "key":[
                {
                    "answer":"helsinki",
                    "correct": 1
                }
            ]
        },
        {
            "answer":"Nursultan",
            "key":[
                {
                    "answer":"nursultan",
                    "correct": 1
                },
                {
                    "answer":"nur-sultan",
                    "correct": 1
                },
                {
                    "answer":"astana",
                    "correct": 0.5
                }
            ]
        }
    ]
}

这是为每个问题更新密钥的代码:

exports.gradeRound = catchAsync(async (req, res, next) => {
  const r = await Round.findById(req.params.rid);
  //for each question in the round
  let newKey;
  for (var i = 0; i < r.questions.length; i++) {
    console.log(`Question ${i + 1} info:`);
    console.log(r.questions[i]);
    console.log();

    console.log(`Key ${i + 1}:`);
    console.log(req.body.key[i].key);
    console.log();

    // ...some deleted code that verifies that the correct question
    // ...is being graded...that part works fine.

    // copy the array from req.body and set the key array for the question
    // The code commented below are other ways I've tried to set the array.

    // req.body.key[i].key.forEach((a) => {
    //   r.questions[i].key.push(a);
    // });

    // r.questions[i].key = req.body.key[i].key;

    newKey = req.body.key[i].key.slice();
    newKey.forEach((el) => {
      r.questions[i].key.push({ ...el });
      console.log(r.questions[i].key);
    });
  }

  const ans = await r.save();

  // this logged the document with empty keys for each question.
  // const newR = await Round.findById(req.params.rid);
  // console.log(newR);

  // ...yet this gave what I would have expected for ans...the round with the 
  // keys populated
  res.status(200).json({
    status: 'success',
    data: ans,
  });
});

有趣的是,每个 console.log 都给了我我所期望的。响应返回了我所期望的结果——“ans”对象中的键数组填充了来自 req.body 的确切值。但是,当我再次查询数据时(从 r.save() 下方注释掉的代码中可以看到),没有填充任何键,当我查看 MongoDBCompass 时也是如此。

我在这里拉头发-我做错了什么?还是我遗漏了一些小细节?

标签: node.jsmongodbmongoosemongodb-query

解决方案


更新 -

显然,Mongoose 没有深入到看到这个数组字段发生了变化(因为它被嵌入到主文档的数组中的对象中),所以为了强制它保存,我在 r.save 正上方添加了这一行():

r.markModified('questions');

然后,当我这样做

const ans = await r.save();

...它看到“问题”被修改并保存。


推荐阅读