How to rename a field that is nested inside an array of objects deep without compromising on performance?

I wanted to rename field inside a nested array of objects which looks like below:

{
    "_id":"63ca455cb7dd228bcb3d85e5"
    "name": "Alex",
    "phoneNumber": "+235946546654",
    "level": 5,
    "workByCateg": [
      {
        "workId": "741qaz852wsx963edc",
        "customWork": [
          {
            "dName": "Status",
            "type": "options",
            "value": "Others"
          },
          {
            "dName": "Appointment",
            "type": "dateTime",
            "value": 1324645625
          },
          {
            "dName": "Notes",
            "type": "status",
            "value": "hi hello how are you.."
          }
        ]
      },
      {
        "workId": "123qaz456wsx789edc",
        "customWork": [
          {
            "dName": "Status",
            "type": "options",
            "value": "Work Done"
          },
          {
            "dName": "Appointment",
            "type": "dateTime",
            "value": 1326546546
          },
          {
            "dName": "Cus-Field",
            "type": "multi-options",
            "value": ["opt1", "opt2"]
          }
        ]
      }
    ]
  }

I want to retain this structure, but do some changes like the following, on the result:

  1. change the field name from “dName” to “name”
  2. remove the field “type” from “customWork” field.

I don’t want to make changes to the database.

The following is the aggregation that I use:

[
    {
      $match: <my_query>
    },
    {
      $unwind: "$workByCateg",
    },
    {
      $set: {
        workByCateg: {
          processId: "$workByCateg.workId",
          customWork: {
            $map: {
              input: "$workByCateg.customWork",
              as: "theField",
              in: {
                name: "$$theField.dName",
                value: "$$theField.value",
              },
            },
          },
        },
      },
    },
    {
      $addFields: {
        "workByCateg.customWork": {
          $ifNull: ["$customWork", "$$REMOVE"],
        },
      },
    },
    {
      $group: {
        _id: "$_id",
        name: { $last: "$name" },
        phoneNumber: { $last: "$phoneNumber" },
        level: { $last: "$level" },
        workByCateg: { $push: "$workByCateg" },
      },
    },
  ]

Here I’m doing unwind first, to change field names, and then im grouping it again to club all “customWork” together under “workByCateg” field.
I feel like the aggregation that i use is an overkill and thinking about performance issues. Any straight forward approach for this?

Any help would be appreciated. Thank you for your time.

Hi @Sooraj_S,
I believe we can take the following approach:

db.workers.updateMany(
  {},
  [
    {
      $set: {
        "workByCateg": {
          $map: {
            input: "$workByCateg",
            as: "work",
            in: {
              workId: "$$work.workId",
              customWork: {
                $map: {
                  input: "$$work.customWork",
                  as: "custom",
                  in: {
                    name: "$$custom.dName",
                    value: "$$custom.value"
                  }
                }
              }
            }
          }
        }
      }
    }
  ]
);

It would be good to test performance on a larger collection, and even adopt some kind of filter and run updateMany in batches.

See if it makes sense and let me know!

Hi, thanks for taking the time and replying.
I’m sorry that i didn’t mention that I don’t want to update the documents. I just want to modify it for the response.

This one updates the docs in the collection right? @Leandro_Domingues

Actually I believe I was the one who made a mistake, you really mentioned that you didn’t want to change the documents in the database, I’m sorry… Yes this script changes the documents in the collection.

Let me see if I can think of something.

Hi @Leandro_Domingues ,
Thanks, this one really helped.

Now, I’m really sorry for not testing out the aggregation method you mentioned.
I used your suggestion inside aggregation, rather than in updateMany, and it worked.

I request you to, if possible, edit your answer and update “updateMany” to “aggreate”, so that it helps others in need.
I’m marking your answer as the solution.

Thanks again. Cheers!

1 Like

Sure!

Here it goes, now without any changes to the database, using the aggregate to return the documents in the desired format.

db.workers.aggregate(
  [
    {
      $set: {
        "workByCateg": {
          $map: {
            input: "$workByCateg",
            as: "work",
            in: {
              workId: "$$work.workId",
              customWork: {
                $map: {
                  input: "$$work.customWork",
                  as: "custom",
                  in: {
                    name: "$$custom.dName",
                    value: "$$custom.value"
                  }
                }
              }
            }
          }
        }
      }
    }
  ]
);
1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.