I’m trying to upsert a document OR update 2 fields in one round trip with an aggregation (or some variation of one of the many update methods) in mongodb.
Example Record I’m trying to upsert:
{ _id: "1", favoriteColor: "blue", updatedAt: 123 }
I want my aggregation/update query+criteria to do the following:
- Fetch document with id: 1
- If the document doesn’t exist, insert it
- If it does exist, check the existing value for the field: ‘favoriteColor’
- If they match, do nothing
- If they’re different, update the field ‘favoriteColor’, and the field ‘updatedAt’
It’s very easy to see how you would do this in multiple API calls, but not so much with one call.
Every option seems to break down when you add the requirement that I must both be able to insert the document if it doesn’t exist, or update 2 fields.
2
Answers
In my opinion, one of the canonical templates to perform upsert would be using
$documents
and$merge
.$documents
with the payload/input documents$merge
to upsert to the collection. For your specific case,on
: we just use_id
, for the first checkwhenNotMatched
:insert
whenMatched
: we use a pipeline here to perform a conditional update based on the value of$$new.favoriteColor
, which refers to your input documents’favoriteColor
field.Mongo Playground for not exist case
Mongo Playground for different favoriteColor field
Mongo Playground for do nothing case
The syntax is slightly different in playground, due to some limitation of playground around
$documents
. The above syntax should work just fine on your shell/application code.You could use the pipeline form of update with the $cond operator for the updatedAt:
This will: