Reputation: 432
I have two arrays of objects in my documents.
{
"profileSpherestatus": [
{
"idf": "B002",
"completedPercentage": 100
},
{
"idf": "B003",
"completedPercentage": 90
},
{
"idf": "B004",
"completedPercentage": 100
}
]
"myGratificacions": [
{
"idb": "B003",
"gratification": 20
},
{
"idb": "B004",
"gratification": 30
}
]
}
I want to add a new object in myGratifications
if there is at least one object in the profileSpherestatus
array where idf
is "B002" and completedPercentage
is 100, and there is not a gratification
with "idb": "B002"
.
The newObject
is:
newObject = {
"idb":"B002",
"gratification":10
}
This is my pipeline:
[
{"$set": {
"myGratifications":
{"$cond": {
"if": {
"$and": [
{"profileSpherestatus":
{"$elemMatch": {"idf": "B002", "completedPercentage": 100}}
},
{"$not":
{"myGratifications":{"$elemMatch": {"idb": "B002"}}}
}
]
},
"then": {
"$concatArrays": ["$myGratifications",[newObject]]
},
"else": "$myGratifications"
}}
}}
]
But $elemMatch
cannot be used inside $set
or $addFields
. Can you help me?
Upvotes: 1
Views: 53
Reputation: 16112
If you are only doing this one update - adding the new element to myGratifications
- then you can add your update-only-if conditions in the filter/match query for update
.
Combine the element checks with any other query you already have, like on _id
, etc. In the update part, you can use the $push
array update operator to add the new element.
It has the added benefit of not doing any update when the document is found but the arrays don't meet the criteria you've defined. May not make much of a difference for a single document update but if you wanted to update a thousands/millions, then documents which exist but don't meet the criteria would be skipped.
db.collection.update({
// match criteria
"$and": [
// other filter criteria START
{
// as an example
"_id": { "$regex": ".*" }
},
// other filter criteria END
// ACTUAL filter criteria to update or not
{
"profileSpherestatus": {
"$elemMatch": {
"idf": "B002",
"completedPercentage": 100
}
}
},
{
"myGratifications": {
"$not": {
"$elemMatch": { "idb": "B002" }
}
}
}
]
},
{
// update operation
"$push": {
"myGratifications": { "idb": "B002", "gratification": 10 }
}
},
{ multi: true }
)
Mongo Playground with additional test docs
Btw, you can still use your current set+concat method for the update part if you want, or have other $set
operations to do. The match/filter query remains the same as above & the update part is similar to your existing then
clause:
[
// update operations
{
"$set": {
"myGratifications": {
"$concatArrays": [
"$myGratifications", [{ "idb": "B002", "gratification": 10 }]
]
}
}
}
]
Upvotes: 1
Reputation: 51450
$elemMatch
is not supported when you use an aggregation pipeline.
Replace the first $elemMatch
condition by checking the $size
of the $filter
array.
Replace the second $elemMatch
condition with $not
$in
.
db.collection.update({ /* match criteria */ },
[
{
"$set": {
"myGratificacions": {
"$cond": {
"if": {
"$and": [
{
$gt: [
{
$size: {
$filter: {
input: "$profileSpherestatus",
cond: {
$and: [
{
$eq: [
"$$this.idf",
"B002"
]
},
{
$eq: [
"$$this.completedPercentage",
100
]
}
]
}
}
}
},
0
]
},
{
"$not": {
$in: [
"B002",
"$myGratificacions.idb"
]
}
}
]
},
"then": {
"$concatArrays": [
"$myGratificacions",
[
{
"idb": "B002",
"gratification": 10
}
]
]
},
"else": "$myGratificacions"
}
}
}
}
])
Note that there is a typo error in your current update query, myGratifications
field doesn't exist in your document, should be myGratificacions
.
Upvotes: 1