Home > Blockchain >  Mongodb rename key in an array of objects
Mongodb rename key in an array of objects

Time:03-26

I am trying to update the name of a key inside an object of an array and annoyed due to the inability to make the queries work. I have tried this How rename nested key in array of object in MongoDB? but I still get the same error I was getting earlier

Here is the document:

[
  {
  "accountCreation": [
      {
        "startDateTime": "",
        "endDateTime": "",
        "isDone": "Yes"
      }
    ]
  }
]

Here is my query:

db.collection.update({}, $rename:{
  "accountCreation.$.isDone":"done",
})

All I am trying to do is rename the isDone key to done. Note that this is just one of the many objects that have this key. I am trying to update all the occurences of the isDone key to done inside the accountCreation

Here is the error I am receiving:

fail to run update: write exception: write errors: [cannot use the part (accountCreation of accountCreation.isDone) to traverse the element

CodePudding user response:

This can be done in two steps(mongoDB 4.2 ):

Step 1: Add the new field "done"

db.collection.update({
   "accountCreation": {
          $exists: true
      }
   },
   [
   {
     "$addFields": {
       accountCreation: {
         "$map": {
           "input": "$accountCreation",
           "as": "ac",
           "in": {
          $mergeObjects: [
          "$$ac",
          {
            "done": "$$ac.isDone"
          }
         ]
        }
      }
     }
   }
 }
],
{
  multi: true
})

Explained:

Add the field "Done"="$isDone" in all array elements where isDone is found.

playground_step_1

Step 2: Remove the old field "isDone":

  db.collection.update({
   "accountCreation.isDone": {
   "$exists": true
  }
 },
 {
  "$unset": {
    "accountCreation.$[x].isDone": true
 }
},
{
  arrayFilters: [
 {
  "x.isDone": {
    $exists: true
  }
}
],
   multi: true
})

Explained:

Define arrayFilter x and remove the old field "isDone" from all array elements where it is found

playground_step_2

( Afcourse Step 1 need to be executed first!!! )

CodePudding user response:

Actually, the answers to the link you provided already stated that $rename does not work with array.

Nevertheless, you could probably achieve your expected behaviour by using an aggregate with update. You will need to use $objectToArray and $arrayToObject to wrangle the objects if you have other fields.

db.collection.update({},
[
  {
    "$project": {
      accountCreation: {
        "$map": {
          "input": "$accountCreation",
          "as": "ac",
          "in": {
            "$objectToArray": "$$ac"
          }
        }
      }
    }
  },
  {
    "$project": {
      accountCreation: {
        "$map": {
          "input": "$accountCreation",
          "as": "ac",
          "in": {
            "$map": {
              "input": "$$ac",
              "as": "kv",
              "in": {
                "$cond": {
                  "if": {
                    $eq: [
                      "$$kv.k",
                      "isDone"
                    ]
                  },
                  "then": {
                    "k": "done",
                    "v": "$$kv.v"
                  },
                  "else": "$$kv"
                }
              }
            }
          }
        }
      }
    }
  },
  {
    "$project": {
      accountCreation: {
        "$map": {
          "input": "$accountCreation",
          "as": "ac",
          "in": {
            "$arrayToObject": "$$ac"
          }
        }
      }
    }
  }
])

Here is the Mongo playground for your reference.

  • Related