Home > Mobile >  MongoDb - Update all properties in an object using MongoShell
MongoDb - Update all properties in an object using MongoShell

Time:12-21

I have a collection with many documents containing shipping prices:

{
  "_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"
  }
}

In pricegrid, all the properties can be different from one grid to another.

I'd like to update all the prices in the field "pricegrid" (price * 1.03 1).

I tried this :

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

Resulting in this error :

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

So I tried with only $mul (planning on doing $inc in another query) :

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

But in that case, I get this error :

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

Could you please direct me on the correct way to write the request ?

CodePudding user response:

You can use an aggregation pipeline in an update. $objectToArray pricegrid to convert it into an array of k-v tuple first. Then, do a $map to perform the computation. Finally, $arrayToObject to convert it back.

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"
      }
    }
  }
])

Here is the Mongo playground for your reference.

CodePudding user response:

You can do it with Aggregation framework:

  • $objectToArray - to transform pricegrid object to array so you can iterate of its items
  • $map to iterate over array generated in previous step
  • $sum and multiply to perform mathematical operations
  • $arrayToObject to transform updated array back to object
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

CodePudding user response:

I might be wrong, but it looks like there's currently no support for this feature - there's actually an open jira-issue that addresses this topic. Doesn't look like this is going to be implemented though.

  • Related