Mongoose:通过 findOneAndUpdate 查询使用嵌套对象数组的总和更新父子数据属性不起作用

Posted

技术标签:

【中文标题】Mongoose:通过 findOneAndUpdate 查询使用嵌套对象数组的总和更新父子数据属性不起作用【英文标题】:Mongoose: Updation of parent-child data attribute with sum of nested object array through findOneAndUpdate query not working 【发布时间】:2021-01-31 19:37:20 【问题描述】:

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


    "_id": ObjectId("5f8af2fc5f23667adf3bbaf2"),
    "score": 2.5,
    "questions": [
            "_id": ObjectId("5f8af30d5f23667adf3bbaf5"),
            "score": 1.5,
        ,
        
            "_id": ObjectId("5f8af3115f23667adf3bbaf8"),
            "score": 1,
            "options": [
                    "_id": ObjectId("5f8af3115f23667adf3bbaf9"),
                    "score": 1,
                    "desc": "description 1"
                ,
                
                    "_id": ObjectId("5f8af3115f23667adf3bbafa"),
                    "score": 0,
                    "desc": "description 2"
                
            ]
        
    ]

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

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

我使用了 @turivishal 在这个答案中提到的下面的猫鼬函数,它可以很好地更新基于问题数组的根分数:

https://***.com/a/64401747/3159714

这里需要注意的是,选项数组中的一些其他属性如desc也需要在同一个调用中更新。

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

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

【问题讨论】:

两个选项中的哪一个?是否有特定选项的输入_id? 作为参考,我需要更新选项 id 5f8af3115f23667adf3bbafa 好的,你能解释一下吗,它总是一个更新选项或多个或整个选项数组,也只是desc字段或更多字段?,为什么我是问,因为我可以提出更好的解决方案。 一次只能更新一个选项,并且可以更新该元素中的任何属性;作为参考,让我们考虑我想更新 desc 和 score。所以根级别的分数和问题级别的对应分数也应该刷新 【参考方案1】: 再添加一个$map 用于选项数组检查条件,如果选项_id 匹配则更新选项对象并使用$mergeObjects 与当前对象合并
let id = mongoose.Types.ObjectId("5f8a94ccc8452643f1498419");

let oid = mongoose.Types.ObjectId("5f8af3115f23667adf3bbafa");
let option = 
  desc: "updated desc"
;

let qid = mongoose.Types.ObjectId("5f8a94e8c8452643f149841c");
let question = 
  score: 1,
  order: 1,
  category: "TEXT",
  options: 
    $map: 
      input: "$$this.options",
      in: 
        $mergeObjects: [
          "$$this",
           $cond: [ $eq: ["$$this._id", oid] , option, ] 
        ]
      
    
  
;

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

Playground

【讨论】:

非常感谢...像魅力一样工作:) 一个问题...如果我只想更新特定选项的描述而不影响任何其他属性,我应该使用什么查询?从上面的查询中删除最后一个 $set 不能在这种情况下使用 试过这个 [ $set: questions: $map: input: "$questions", in: $mergeObjects: [ "$$this.options", $cond: [ $eq: ["$$this._id", ObjectId(oid)] , "desc" : "xyx", ], , ], , , , , ] 但没有工作 像这样使用arrayFilters playground

以上是关于Mongoose:通过 findOneAndUpdate 查询使用嵌套对象数组的总和更新父子数据属性不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Mongoose:findOneAndUpdate 不返回更新的文档

Mongoose:findOneAndUpdate 不返回更新的文档

Mongoose:findOneAndUpdate 不返回更新的文档

Mongoose - 使用 findOneAndUpdate 更新子文档

Mongoose `findOneAndUpdate` 回调不传递更新的文档

Mongoose `findOneAndUpdate` 回调不传递更新的文档