Got it, I think. But it needs https://docs.mongodb.com/manual/tutorial/update-documents-with-aggregation-pipeline/ from 4.2.
It’s kind of complicated. It is going to be a update pipeline with a $set stage that uses $map. It will update the products array into a temporary updated_products array, but you could $map in itself. I like the temp. field as in Tip3.express
// Apply the mapping only to document that needs it (see Tip 2)
update_query =
{ "products.product.type" : "plan" ,
"products.product.plan_group" : { "$type" : "string" }
}
// update_plan_group replace plan_group which is a string to an array but keeps the
// old price and type ($$item is the ***as*** of the $map)
update_plan_group =
{ "product" :
{ "plan_group" : [ "$$item.product.plan_group" ] ,
"price" : "$$item.product.price" ,
"type" : "$$item.product.plan"
}
}
// We want to only alter the product when plan_group is a string. You might want to
// check for type:plan in case you have string plan_group for something else than plan
plan_group_is_string ={ "$eq" : [ { "$type":"$$item.product.plan_group"} , "string" ] }
// We map plan_group only when plan_group is a string
conditional_mapping =
{ '$cond' :
{ 'if' : plan_group_is_string ,
"then" : update_plan_group ,
"else" : "$$item"
}
}
// Map the products array. This is where we defined $$item used above.
map =
{ "$map" :
{ "input" : "$products" ,
"as" : "item" ,
"in" : conditional_mapping
}
}
// Let's do it in a temporary array named updated_products. See Tip 3.
// You will need to move updated_products into products in
// another step but you get the chance to verify the result before and make any
// without losing the original values
update_pipeline = [ { "$set" : { "mapped_products" : map } } ]
c.updateMany( updateQuery , update_pipeline )upda
// The complete update_pipeline is:
[ { '$set':
{ mapped_products:
{ '$map':
{ input: '$products',
as: 'item',
in:
{ '$cond':
{ if: { '$eq': [ '$$item.product.type', 'plan' ] },
then:
{ product:
{ plan_group: [ '$$item.product.plan_group' ],
price: '$$item.product.price',
type: '$$item.product.plan' } },
else: '$$item' } } } } } } ]
// The updated document is
{ _id: 1,
number: 'CC850732',
products:
[ { product: { plan_group: 'Old', price: 1999, type: 'plan' } },
{ product: { price: 1999, type: 'other' } },
{ product: { plan_group: 'New', price: 1999, type: 'plan' } } ],
updated_products:
[ { product: { plan_group: [ 'Old' ], price: 1999 } },
{ product: { price: 1999, type: 'other' } },
{ product: { plan_group: [ 'New' ], price: 1999 } } ] }
Enjoy!