I want to achieve $sum with $cond by having $or on property:
db.collectionName.aggregate(
{
"$group": {
"_id":'$created_at',
"count": {"$sum": 1},
"count_failure": {
"$sum": {
"$cond": [
{
"$id":
{ "$in": [ 0,100,101,102,103,104,105 ] }
},
1,
0
]
}
}
}
}
)
But error says: Invalid operator "$id"
What's wrong with syntax? Or I am writing query wrongly.
Currently I am achieving this by:
db.collectionName.aggregate(
{
"$group": {
"_id":'$created_at',
"count": {"$sum": 1},
"count_failure": {
"$sum": {
"$cond": [
{
"$or":[
{ "$eq": [ "$id", 0 ] },
{ "$eq": [ "$id", 100 ]},
{ "$eq": [ "$id", 101 ]},
{ "$eq": [ "$id", 102 ]},
{ "$eq": [ "$id", 103 ]},
{ "$eq": [ "$id", 104 ]},
{ "$eq": [ "$id", 105 ]}
]
},
1,
0
]
}
}
}
}
)
The comparison on $setIsSubset
is a shorter option than the $or
condition you are using, though it's still basically valid to do what you are doing.
The only catch with $setIsSubset
is that each argument is an array so you need to convert the single element as a single element array. This is easy enough using $map
:
db.collectionName.aggregate([
{ "$group": {
"_id": "$createdAt",
"count": { "$sum": 1 },
"count_failure": {
"$sum": {
"$cond": [
{ "$setIsSubset": [
{ "$map": {
"input": ["A"],
"as": "el",
"in": "$id"
}},
[ 0,100,101,102,103,104,105 ],
]},
1,
0
]
}
}
}}
])
Or if you prefer, then match the array of arguments against the singular value instead, with $anyElementTrue
:
db.collectionName.aggregate([
{ "$group": {
"_id": "$createdAt",
"count": { "$sum": 1 },
"count_failure": {
"$sum": {
"$cond": [
{ "$anyElementTrue": { "$map": {
"input": [ 0,100,101,102,103,104,105 ],
"as": "el",
"in": { "$eq": [ "$$el", "$id" ] }
}}},
1,
0
]
}
}
}}
])
Where the $map
is rather traversing the arguments to match to the singular rather than forcing the singular into an array.
And of course since either form is essentially supplying true/false
to the $cond
then you can just reverse the logic with $not
where required:
db.collectionName.aggregate([
{ "$group": {
"_id": "$createdAt",
"count": { "$sum": 1 },
"count_failure": {
"$sum": {
"$cond": [
{ "$not": [{ "$anyElementTrue": { "$map": {
"input": [ 0,100,101,102,103,104,105 ],
"as": "el",
"in": { "$eq": [ "$$el", "$id" ] }
}}}]},
1,
0
]
}
}
}}
])
It really depends on how you look at it, but simply as supplied arguments then you don't really gain anything over the original form with $or
. It might look a little cleaner and "easier to type", but typically I would not be "typing" such logic into the aggregation pipeline directly, but rather generating that part of the structure based on a plain list in the first place:
i.e
var failList = [ 0,100,101,102,103,104,105 ];
var orCondition = failList.map(function(el) {
return { "$eq": [ "$id", el ] }
})
And then just using the re-mapped array content in the pipeline definition:
{ "$group": {
"_id": "$createdAt",
"count": { "$sum": 1 },
"count_failure": {
"$sum": {
"$cond": [
{ "$or": orCondition },
1,
0
]
}
}
}}
])
Whatever way you look at it, remember it's all just data structures and you have basic processes for manipulating. Both inside the pipeline processing and also in the pipeline construction itself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With