1

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
  ]
}
3
  • 3
    possible duplicate stackoverflow.com/questions/9122966/… Commented Aug 21, 2018 at 17:48
  • Could you post sample document from customers collection ? Commented Aug 21, 2018 at 17:49
  • The answers in the other question are very old. Wondering if there is new functionality for Mongo to handle this kind of transformation now? Commented Aug 21, 2018 at 17:54

1 Answer 1

5

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.

Sign up to request clarification or add additional context in comments.

6 Comments

I added more detail to my data structure. Is there a way to do this without overriding other fields within the plans array? Sorry, should have been more specific to begin with.
@Muirik that's why I wanted to see the structure. So the simplest way would be to specify them as well like in my edited answer. Let met know if that's okay for you. Otherwise we can try some tricks with $mergeObjects :)
Anyway, I've added the "dynamic" approach
@mickl Works amazingly! You saved me potential hours of work :D thank you!!!
Sorry if I am late @mickl, but why do we need $$plan.k in $ne? is that some field name or what? trying to implement your second solution. Thanks in advance!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.