1

I have this document structure

{
    "_id": <OBJECT_ID>,
    "orders": [
         {
              "userId": 1,
              "handleName": "John Doe",
              "orderAmount": 3,
              "others": [
                   {
                        "userId": 1,
                        "handleName": "John Doe"
                   },
                   {
                        "userId": 2,
                        "handleName": "Maria Gigante"
                   }
              ]
         },
         {
              "userId": 2,
              "handleName": "Maria Gigante",
              "orderAmount": 2,
              "others": [
                   {
                        "userId": 1,
                        "handleName": "John Doe"
                   },
                   {
                        "userId": 2,
                        "handleName": "Maria Gigante"
                   }
              ]
         },
         {
              "userId": 1,
              "handleName": "John Doe",
              "orderAmount": 4,
              "others": [
                   {
                        "userId": 1,
                        "handleName": "John Doe"
                   },
                   {
                        "userId": 2,
                        "handleName": "Maria Gigante"
                   }
              ]
         },
         {
              "userId": 3,
              "handleName": "John Doe",
              "orderAmount": 4,
              "others": [
                   {
                        "userId": 1,
                        "handleName": "John Doe"
                   },
                   {
                        "userId": 2,
                        "handleName": "Maria Gigante"
                   }
              ]
         }
    ]
}

I would like to update all the objects that has the userId of 1 and handleName of John Doe. Note that objects can have the same handle names but different user id. That is why I need to match it with the userId first.

For example I want to change the handle name to Donald Stark

I would like to have this result:

{
    "_id": <OBJECT_ID>,
    "orders": [
         {
              "userId": 1,
              "handleName": "Donald Stark",
              "orderAmount": 3,
              "others": [
                   {
                        "userId": 1,
                        "handleName": "Donald Stark"
                   },
                   {
                        "userId": 2,
                        "handleName": "Maria Gigante"
                   }
              ]
         },
         {
              "userId": 2,
              "handleName": "Maria Gigante",
              "orderAmount": 2,
              "others": [
                   {
                        "userId": 1,
                        "handleName": "Donald Stark"
                   },
                   {
                        "userId": 2,
                        "handleName": "Maria Gigante"
                   }
              ]
         },
         {
              "userId": 1,
              "handleName": "Donald Stark",
              "orderAmount": 4,
              "others": [
                   {
                        "userId": 1,
                        "handleName": "Donald Stark"
                   },
                   {
                        "userId": 2,
                        "handleName": "Maria Gigante"
                   }
              ]
         },
         {
              "userId": 3,
              "handleName": "John Doe",
              "orderAmount": 4,
              "others": [
                   {
                        "userId": 1,
                        "handleName": "Donald Stark"
                   },
                   {
                        "userId": 2,
                        "handleName": "Maria Gigante"
                   }
              ]
         }
    ]
}

How is this achieved?

Update: I forgot that I also have another inner array that I also want to be updated.

Paul Ryan Lucero
  • 521
  • 1
  • 3
  • 16

2 Answers2

3

we can use $[identifier] operator to update specific objects in the array

so your update query should look something like

db.collection.updateOne(
    { _id: <OBJECT_ID> }, // filter part, add the real objectId here
    { $set: { 'orders.$[order].handleName': 'Donald Stark' } }, // update part
    { arrayFilters: [{ 'order.userId': 1, 'order.handleName': 'John Doe' }] 
})

$[order] to update only the objects that match the conditions in the array filters


Update

If you have an inner array, and you need to do the same thing for the elements inside that inner array, we could use something like that

db.collection.updateOne(
    { _id: <OBJECT_ID> }, // filter part, add the real objectId here
    { $set: { 
        'orders.$[order].handleName': 'Donald Stark', // to set the handleName in the elements of the outer array
        'orders.$[].others.$[other].handleName': 'Donald Stark' // to set the handleName in the elements of the inner array
    } },
    { arrayFilters: [{ 'order.userId': 1, 'order.handleName': 'John Doe' }, { 'other.userId': 1, 'other.handleName': 'John Doe' }] }
)

we used $[] to loop over all the elements in the orders array, then use $[other] to update specific elements in the inner array according to the new condition in the array filters

hope it helps

Mohammed Yousry
  • 2,134
  • 1
  • 5
  • 7
2

Would something like that solve your problem ?

d = {
    "_id": <OBJECT_ID>,
    "orders": [
         {
              "userId": 1,
              "handleName": "John Doe",
              "orderAmount": 3
         },
         {
              "userId": 2,
              "handleName": "Maria Gigante",
              "orderAmount": 2
         },
         {
              "userId": 1,
              "handleName": "John Doe",
              "orderAmount": 4
         },
         {
              "userId": 3,
              "handleName": "John Doe",
              "orderAmount": 4
         }
    ]
}

def change_name(usr_id, old_name, new_name):
    for usr in d['orders']:
        if usr['userId'] == usr_id and usr['handleName'] == old_name:
            usr['handleName'] = new_name

change_name(1, 'John Doe', 'Donald Stark')
Donatien
  • 151
  • 6