I have a mongo document like this.
{
"_id": "a74e283a",
"data": [
{
"origin": "apple",
"edit": "fruit"
},
{
"origin": "grape",
"edit": "fruit"
},
{
"origin": "melon",
"edit": "fruit"
}
]
}
I want to be able to insert and update the array with a single mongo command and not use a conditional within a find() then run insert() and update() depending on the presence of the object.
example if I update the array with this:
{
"data": [
{
"origin": "apple",
"edit": "fruit_edit"
},
{
"origin": "pear",
"edit": "fruit"
}
]
}
Result must be like this:
{
"_id": "a74e283a",
"data": [
{
"origin": "apple",
"edit": "fruit_edit"
},
{
"origin": "grape",
"edit": "fruit"
},
{
"origin": "melon",
"edit": "fruit"
},
{
"origin": "pear",
"edit": "friut"
}
]
}
CodePudding user response:
You can update with an aggregation pipeline. Put a $set
in the aggregation pipeline and use $reduce
to process the upsert logic.
In the $reduce
, put your edit array as the initial value. When there is a match, just keep the accumulator value as the edit is already in the accumulator. When there is unmatched, append the array entry to the accumulator.
db.collection.update({},
[
{
$set: {
data: {
"$reduce": {
"input": "$data",
"initialValue": // assign your edit data as init value
[
{
"origin": "apple",
"edit": "fruit_edit"
},
{
"origin": "pear",
"edit": "fruit"
}
],
"in": {
"$cond": {
"if": {
$in: [
"$$this.origin",
"$$value.origin"
]
},
"then": "$$value",
"else": {
"$concatArrays": [
"$$value",
[
"$$this"
]
]
}
}
}
}
}
}
}
])
Here is the Mongo playground for your reference.
CodePudding user response:
Query
- put you new data on "ndata"
- one more variable is defined "ndata_origin" to do the project 1 time only
- this filters the old data, and remove all the new-data => old-without-new
- concat old-without-new newdata
update({},
[{"$set":
{"data":
{"$let":
{"vars":
{"ndata":
[{"origin": "apple", "edit": "fruit_edit"},
{"origin": "pear", "edit": "fruit"}]},
"in":
{"$let":
{"vars": {"ndata_origin": "$$ndata.origin"},
"in":
{"$concatArrays":
[{"$filter":
{"input": "$data",
"cond":
{"$not": [{"$in": ["$$this.origin", "$$ndata_origin"]}]}}},
"$$ndata"]}}}}}}}])