首页 > 解决方案 > Mongoose:通过 findOneAndUpdate 查询使用对象数组的总和更新根数据属性不起作用

问题描述

我正在尝试使用 Node mongoose lib 更新 mongo 集合中的数组元素之一。这是我的 mongo 架构的样子:

{
    "_id": ObjectId("5f8a94ccc8452643f1498419"),
    "private": false,
    "score": 2000,
    "questions": [{
        "_id": ObjectId("5f8a94e8c8452643f149841c"),
        "order": 1,
        "category": "TEXT",
        "definition": "about us",
        "score": 1,
    }, {
        "_id": ObjectId("5f8a94e8c8452643f149841d"),
        "order": 2,
        "category": "HTML",
        "definition": "about us",
        "score": 0.5
    }]
}

我正在更新问题数组中的分数,要更新的根数组的分数属性是数组分数的总和,即

root score => question array1.score + array2.score

我使用了下面的猫鼬功能:

  Model.findOneAndUpdate(
    {
      _id: id,
      "questions._id": qid,
    },
    {
     '$set': {
          'questions.$.order': 1,
          'questions.$.score': 1,
          'questions.$.type': 'HTML',
          '$sum': { 'score': 'questions.score' }
      }
    })

虽然所有其他属性都在更新,但根分数永远不会更新

注意:$setoninsert不是一个选项,因为在这种情况下,upsert始终为false

这是否有可能使用单个查询来执行这两个更新?

标签: node.jsmongodbexpressmongoosemongodb-query

解决方案


从 MongoDB 4.2 开始,您可以将更新与聚合管道一起使用,

  • $set更新 id 匹配的匹配问题qid
  • $setquestions从数组的分数更新根分数
let id = mongoose.Types.ObjectId("5f8a94ccc8452643f1498419");
let qid = mongoose.Types.ObjectId("5f8a94e8c8452643f149841c");
let question = {
  score: 1,
  order: 1,
  category: "TEXT"
};

Model.findOneAndUpdate(
  { _id: id },
  [{
    $set: {
      questions: {
        $map: {
          input: "$questions",
          in: {
            $mergeObjects: [
              "$$this",
              {
                $cond: [
                  { $eq: ["$$this._id", qid] },
                  question, // add update fields in object
                  {}
                ]
              }
            ]
          }
        }
      }
    }
  },
  {
    $set: {
      score: {
        $reduce: {
          input: "$questions",
          initialValue: 0,
          in: { $add: ["$$value", "$$this.score"] }
        }
      }
    }
  }]
)

操场


推荐阅读