使用 $cond 切换更新管道中的嵌套数组值

Posted

技术标签:

【中文标题】使用 $cond 切换更新管道中的嵌套数组值【英文标题】:Toggle nested array value in update pipeline with $cond 【发布时间】:2022-01-07 10:10:06 【问题描述】:

我正在尝试切换喜欢文档中 cmets 数组中评论的人的姓名。

比文字更形象化:Mongo Playground Link


解释

假设我有一个文档


    "id": 1,
    "comments": [
      
        "id": 1,
        "text": "Comment 1",
        "likedBy": [
          "Tomato",
          "Potato"
        ],
        
      ,
      
        "id": 2,
        "text": "Comment 2",
        "likedBy": [
          "Carrot"
        ],
        
      ,
      
    ],
    
  ,

我想在特定评论上“切换”likedBy 值“Potato”,与文档中的 comments.id 匹配。


到目前为止,我想出了这个

db.collection.update(
  id: 1,
  "comments.id": 1,
  
,
[
  
    $set: 
      "comments.likedBy": 
        $cond: [
          
            $in: [
              "Potato",
              "$comments.likedBy"
            ]
          ,
          
            $setDifference: [
              "$comments.likedBy",
              [
                "Potato"
              ]
            ]
          ,
          
            $concatArrays: [
              "$comments.likedBy",
              [
                "Potato"
              ]
            ]
          
        ],
        
      ,
      
    ,
    
  
])

预期输出:


    "id": 1,
    "comments": [
      
        "id": 1,
        "likedBy": [
           "Tomato",
           //!! Potato is removed from here
        ],
        "text": "Comment 1"
      ,
      
        "id": 2,
        "likedBy": [
          "Carrot"
        ],
        "text": "Comment 2"
      
    ],

  

但是,我得到的结果不正确。我有一种感觉,我在使用位置运算符时做错了。

【问题讨论】:

您希望在 id=1、comment.id=1、likedBy 上添加“Potato”(如果缺少),或者删除“Potato”(如果存在)? 【参考方案1】:

查询

这会从likeBy 中删除"Potato",如果它存在,则添加"Potato" $map 在 cmets 上,如果 comment.id=1 添加/删除 "Potato" 否则留下评论 下面代码中$$this是注释子文档

*不确定这是否正是您需要的,但会产生您想要的结果,并且看起来像您的查询。

*关于路径,“$cmets.likedBy”是一个数组,包含来自所有 cmets 的所有 likedBy 数组,$map 波纹管 $$this.likedBy 用于仅包含特定评论的 likedBy,我认为这是问题所在。

Test code here

update(
"id": 1,"comments.id": 1,
["$set": 
    "comments": 
      "$map": 
        "input": "$comments",
          "in": 
          "$cond": 
            ["$eq": ["$$this.id", 1],
              "$mergeObjects": 
                ["$$this",
                  "likedBy": 
                    "$cond": 
                      ["$in": ["Potato", "$$this.likedBy"],
                       "$setDifference": ["$$this.likedBy", ["Potato"]],
                       "$concatArrays": ["$$this.likedBy", ["Potato"]]]],
              "$$this"]])

【讨论】:

在这种情况下,由于管道已经在检查"$eq": ["$$this.id", 1],从查找查询中删除"comments.id": 1 是否安全? 它不仅安全而且更好,保留它的唯一原因是如果你有太多的 id=1(我的意思是根 id)并且在comment.id 上有一个索引。我认为您不需要它,但我保留了它,因为我不知道您的数据如何。如果没有comment.id=1,则查询永远不会更改评论,因此它是安全的 感谢您的解释。效果很好。

以上是关于使用 $cond 切换更新管道中的嵌套数组值的主要内容,如果未能解决你的问题,请参考以下文章

带有 $cond 的 MongoDB 聚合管道 $addFields - 无法使用变量

两个tf.data.Dataset可以共存并由tf.cond()控制

使用管道中的数组中的对象值执行 $lookup

如何使用来自html的异步管道获取可观察对象的嵌套值

从 azure devops 管道更新变量组

mongodb aggregate