MongoDb - 使用 Mongo Shell 更新 object 中的所有属性

MongoDb - Update all properties in an object using MongoShell

我有一个 collection,其中包含许多包含运费的文件:

{
  "_id": {
    "$oid": "5f7439c3bc3395dd31ca4f19"
  },
  "adapterKey": "transport1",
  "pricegrid": {
    "10000": 23.66,
    "20000": 23.75,
    "30000": 23.83,
    "31000": 43.5,
    "40000": 44.16,
    "50000": 49.63,
    "60000": 50.25,
    "70000": 52,
    "80000": 56.62,
    "90000": 59,
    "100000": 62.5,
    "119000": 68.85,
    "149000": 80,
    "159000": 87,
    "179000": 94,
    "199000": 100.13,
    "249000": 118.5,
    "299000": 138.62,
    "999000": 208.63
  },
  "zones": [
    "25"
  ],
  "franco": null,
  "tax": 20,
  "doc_created": {
    "$date": "2020-09-30T07:54:43.966Z"
  },
  "idConfig": "0000745",
  "doc_modified": {
    "$date": "2020-09-30T07:54:43.966Z"
  }
}

pricegrid中,所有属性都可以从一个网格到另一个不同。

我想更新“pricegrid”字段中的所有价格(价格 * 1.03 + 1)。

我试过了:

db.shipping_settings.updateMany(
  { 'adapterKey': 'transport1' },
  { 
    $mul: { 'pricegrid.$': 1.03 }, 
    $inc: { 'pricegrid.$': 1}
  }
)

导致此错误:

MongoServerError: Updating the path 'pricegrid.$' would create a conflict at 'grille.$'

所以我尝试只使用 $mul(计划在另一个查询中执行 $inc):

db.livraison_config.updateMany(
  { 'adapterKey': 'transport1' },
  { 
    $mul: { 'pricegrid.$': 1.03 }
  }
)

但在那种情况下,我得到这个错误:

MongoServerError: The positional operator did not find the match needed from the query.

能否请您指导我编写请求的正确方法?

我可能错了,但看起来目前不支持此功能 - 实际上有一个开放的 jira-issue 解决了这个主题。不过看起来这不会被实施。

您可以在更新中使用聚合管道。 $objectToArray pricegrid 先把它转成k-v元组的数组。然后,做一个 $map 来执行计算。最后,$arrayToObject把它转换回来。

db.collection.update({
  "adapterKey": "transport1"
},
[
  {
    $set: {
      pricegrid: {
        "$objectToArray": "$pricegrid"
      }
    }
  },
  {
    "$set": {
      "pricegrid": {
        "$map": {
          "input": "$pricegrid",
          "as": "p",
          "in": {
            "k": "$$p.k",
            "v": {
              "$add": [
                {
                  "$multiply": [
                    "$$p.v",
                    1.03
                  ]
                },
                1
              ]
            }
          }
        }
      }
    }
  },
  {
    $set: {
      pricegrid: {
        "$arrayToObject": "$pricegrid"
      }
    }
  }
])

这里是Mongo playground供您参考。

您可以使用聚合框架来完成:

  • $objectToArray - 将 pricegrid 对象转换为数组,以便您可以迭代其项目
  • $map 遍历上一步生成的数组
  • $summultiply 执行数学运算
  • $arrayToObject 将更新的数组转换回对象
db.collection.update({
  "adapterKey": "transport1"
},
[
  {
    "$set": {
      "pricegrid": {
        "$arrayToObject": {
          "$map": {
            "input": {
              "$objectToArray": "$pricegrid"
            },
            "in": {
              k: "$$this.k",
              v: {
                "$sum": [
                  1,
                  {
                    "$multiply": [
                      "$$this.v",
                      1.02
                    ]
                  }
                ]
              }
            }
          }
        }
      }
    }
  }
],
{
  "multi": true
})

Working example