【问题标题】:Use a field's value and add it to a new field in an array - Mongodb使用字段的值并将其添加到数组中的新字段 - Mongodb
【发布时间】:2022-10-25 09:59:46
【问题描述】:

我试图把这个

{
   "fooList" : [
      {
         "bar" : {
            "baz" : 100
         }
      },
      {
         "bar" : {
            "baz" : 200
         }
      }
   ]
},
{
   "fooList" : [
      {
         "bar" : {
            "baz" : 300
         }
      },
      {
         "bar" : {
            "baz" : 400
         }
      }
   ]
}

进入这个:

{
   "fooList" : [
      {
         "baz" : 100,
         "bar" : {
            "baz" : 100
         }
      },
      {
         "baz" : 200,
         "bar" : {
            "baz" : 200
         }
      }
   ]
},
{
   "fooList" : [
      {
         "baz" : 300,
         "bar" : {
            "baz" : 300
         }
      },
      {
         "baz" : 400,
         "bar" : {
            "baz" : 400
         }
      }
   ]
}

如您所见,我实际上只是将baz 及其值从bar 中复制出来,但我的问题是它发生在数组中。

db.getCollection(<collection_name>).updateMany(
    {}, 
    { $set: { 'fooList.$[element].baz' : '$fooList.$[element].bar.baz' } },
    { upsert: true ,
      arrayFilters: [{'element.bar' : { $exists : true }}]
    }
)

但这只会将字符串$fooList.$[element].bar.baz设置成baz,通过结果可以看出这里

[
  {
    "_id": ObjectId("5a934e000102030405000000"),
    "fooList": [
      {
        "bar": {
          "baz": 100
        },
        "baz": "$fooList.$[element].bar.baz"
      }
    ]
  }
]

谁能告诉我我可能做错了什么,或者这是否可能?谢谢

【问题讨论】:

  • 如果还不够清楚,上面的示例只是集合中的文档。

标签: arrays mongodb mongodb-query


【解决方案1】:

您可以在 mongoDB 4.2+ 的更新中使用聚合管道来执行此操作,如下所示:

db.collection.update({},
[
{
$set: {
  fooList: {
    $map: {
      input: "$fooList",
      in: {
        $mergeObjects: [
          "$$this",
          {
            $cond: [
              {
                $ne: [
                  "$$this.bar.baz",
                  undefined
                ]
              },
              {
                baz: "$$this.bar.baz"
              },
              {}
            ]
          }
        ]
       }
      }
     }
    }
   }
  ],
 {
    multi: true
 })

解释:

  1. 您 $set $map-ping 数组文档并根据嵌套元素“bar.baz”存在的条件进行合并,然后添加对象 baz 等于取自 bar.baz 的值。
  2. 为匹配更新查询过滤器的所有文档添加 multi:true 或者您可以使用 updateMany()

    playground

    不幸的是,当您将更新与聚合管道一起使用时,arrayFilters 是不可能的......

    对于早期的 mongodb 版本,它看起来像这样:

       db.collection.find({}).forEach(function(d){ var newfooList=[];d.fooList.forEach(function(s){ s["baz"]=s["bar"]["baz"]; printjson(s);newfooList.push(s);  }); d["fooList"]=newfooList ; db.collection.save(d) })
    

【讨论】:

  • 是否有可能在 4.0 版本中得到这个答案?
  • 在我的答案中添加了一个选项
  • 这适用于我的版本,尽管当我可以升级时,您的第一个解决方案非常棒。再次感谢!
【解决方案2】:

这是一个变体,演示了 v4.4“合并到自身”功能,它将aggregate 变成了update。当您想要处理所有文档时,这是一种有用的方法,因为它消除了update 所需的“无过滤器”({})和{multi:true} 位。

db.foo.aggregate([
    // The $map/$mergeObjects is the SAME as the answer above, just with a little
    // more compact format.  It is import to $project here, NOT $addFields, because
    // we seek to limit the pipeline to just _id (comes along automatically) and 
    // the fooList:
    {$project: {
        fooList: {$map: {
            input: "$fooList",
                in: {$mergeObjects: [
                        "$$this",
                        {$cond: [
                            {$ne: ["$$this.bar.baz", undefined]},
                            {baz: "$$this.bar.baz"},
                            {}  // else empty object                                          
                        ]}
                     ]}
        }}
    }}

    //  ...and now, using _id as the key (fast!), merge fooList back into doc:
    ,{$merge: {
        into: "foo",
        on: [ "_id" ],
        whenMatched: "merge",
        whenNotMatched: "fail"
    }}
]);

【讨论】:

  • 4.0版能得到答案吗?
猜你喜欢
  • 2020-04-28
  • 1970-01-01
  • 2015-04-23
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 2018-06-22
  • 2020-06-29
相关资源
最近更新 更多