Muirik
Muirik

Reputation: 6289

Renaming Field Within an Array in MongoDB

I need to update the name of field in a collection. The problem is that the field in question is within an array. So I'm trying to determine the correct way do this. I tried this to accomplish renaming the field that exists within the "plans" array: :

db.customers.updateMany( {}, { $rename: { "plans" : { "subscriptionType": "membershipType" } } } );

But this won't work. What's the correct way to handle this kind of transformation of a field within an array?

The data looks like this:

{
  _id: 123,
  prop1: value,
  prop2: value,
  prop3: value,
  plans: [
    subscriptionType: value,
    otherProp: value,
    otherProp: value
  ]
}

Upvotes: 1

Views: 3569

Answers (1)

mickl
mickl

Reputation: 49945

You can use Aggregation Framework's $addFields to override plans field and $map operator to rename field inside an array. Then you can use $out to override existing collection:

db.customers.aggregate([
    {
        $addFields: {
            plans: {
                $map:{
                    input: "$plans",
                    as: "plan",
                    in: {
                        membershipType: "$$plan.subscriptionType",
                        otherField: "$$plan.otherField",
                        otherField2: "$$plan.otherField2"
                    }
                }
            }
        }
    },
    {
        $out: "customers"
    }
])

Alternatively you can do that dynamically. In this solution you don't have to explicitly specify other field names:

db.customers.aggregate([
    {
        $addFields: {
            plans: {
                $map:{
                    input: "$plans",
                    as: "plan",
                    in: {
                        $mergeObjects: [
                            { membershipType: "$$plan.subscriptionType" },
                            { 
                                $arrayToObject: {
                                    $filter: {
                                        input: { $objectToArray: "$$plan" },
                                        as: "plan",
                                        cond: { $ne: [ "$$plan.k", "subscriptionType" ] }
                                    }
                                } 
                            }
                        ]
                    }
                }
            }
        }
    },
    {
        $out: "customers"
    }
])

Using $objectToArray to $filter out old key-value pair and the using $mergeObjects to combine that filtered object with new renamed field.

Upvotes: 5

Related Questions