I have the following structure (subset):
{"values"=>
[{"foo"=>"12"},
{"foo"=>"34"},
{"foo"=>"56"},...]}
and I want to convert the fields from string to decimal like this
db.foos.updateMany(
{ "values" => { "$type": "array" } },
{ "$set": { "values.$[element].foo": { "$toDecimal": "$values.$[element].foo" } } },
arrayFilters: [{ "element.foo": { "$type": "string" } }]
)
but I'm getting a literal { "$toDecimal": "$values.$[element].foo" } }
written to the field.
(I need the string filter to be able to add a $trim
later (something like { '$toDecimal': { '$trim': { input: "$foo" } } }
))
What am I doing wrong?
In MongoDB update query, you can't update value by referencing the field name.
You should look for update with aggregation pipeline.
db.foos.update({
"values": {
"$type": "array"
}
},
[
{
"$set": {
"values": {
"$map": {
"input": "$values",
"in": {
"$cond": {
"if": {
"$eq": [
{
"$type": "$$this.foo"
},
"string"
]
},
"then": {
"$mergeObjects": [
"$$this",
{
"foo": {
"$toDecimal": {
"$trim": {
"input": "$$this.foo"
}
}
}
}
]
},
"else": "$$this"
}
}
}
}
}
}
])
For aggregate query:
$match
- Filter document$set
- Set values
field. Iterate element in values
array and transform foo
value to Decimal.$merge
- Merge the output of the aggregation pipeline to collection by _id
.db.foos.aggregate([
{
"$match": {
"$expr": {
"$eq": [
{
"$type": "$values"
},
"array"
]
}
}
},
{
"$set": {
"values": {
"$map": {
"input": "$values",
"in": {
"$cond": {
"if": {
"$eq": [
{
"$type": "$$this.foo"
},
"string"
]
},
"then": {
"$mergeObjects": [
"$$this",
{
"foo": {
"$toDecimal": {
"$trim": {
"input": "$$this.foo"
}
}
}
}
]
},
"else": "$$this"
}
}
}
}
}
},
{
"$merge": {
"into": "foos",
"on": "_id",
"whenMatched": "replace"
}
}
])