I am executing an update on a complex document in DocumentDB. I want to only update changed fields, without setting the object (and/or any nested objects) explicitly, to avoid overwriting existing data.
I am using TypeScript, and have written a function that rewrites the update to use dot notation for every field (to avoid overwriting objects).
The issue is that the document’s fields may be null, so updating foo.bar
fails if foo
is null
.
I have tried adding $ifNull
to the update query:
db.collection.updateOne(
{ _id: 1 },
{
$set: {
"foo": { $ifNull: ["$foo", {}] },
"foo.bar": "value1"
}
}
)
That doesn’t work – if foo
is not null, then setting foo
to $ifnull: ['$foo', {}]
and then foo.bar
in the same update fails, since it results in two updates to the foo.bar
field in the same operation:
Cannot update 'foo.bar' and 'foo.bar' at the same time
The proper way to solve this would be an update using an aggregation pipeline using $mergeObjects
, but DocumentDB does not support updates with an aggregation pipeline.
What are my options here? I want the solution to be as generic as possible and not require any knowledge about the schema or the data, so I could use it for all of my updates.
2
Answers
I would go with 2 queries, potentially with bulk write:
I would say the most canonical way would be using an aggregation to wrangle your data and iterate through the aggregation output to update back to the collection one by one. In this way you can leverage most of the supported aggregation API in AWS documentDB. Potentially if you are doing a lot of updates, you will want to wrap them in bulk operations too
Mongo Playground to see the wrangle result