Как использовать $in или $nin в агрегации mongo $group $cond
Я хочу достичь $ sum с $cond, имея $или на свойстве:
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
]
}
}
}
}
)
но ошибка говорит: Invalid operator "$id"
что случилось с синтаксисом? Или я пишу запрос неправильно.
В настоящее время я достигаю этого:
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
]
}
}
}
}
)
3 ответов
по сравнению с $setIsSubset
является более коротким вариантом, чем $or
условие, которое вы используете, хотя оно по-прежнему в основном действительно для того, что вы делаете.
единственный улов с $setIsSubset
заключается в том, что каждый аргумент является массивом, поэтому вам нужно преобразовать один элемент в один массив элементов. Это достаточно легко с помощью $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
]
}
}
}}
])
или, если хотите, сопоставьте массив аргументов с сингулярным значением вместо этого, с $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
]
}
}
}}
])
здесь $map
скорее пересекает аргументы, чтобы соответствовать сингулярному, а не принуждает сингулярное в массив.
и конечно, так как любая форма является, по сути, поставляя true/false
до $cond
тогда вы можете просто изменить логику с $not
там, где требуется:
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
]
}
}
}}
])
это действительно зависит от того, как вы смотрите на это, но просто как предоставленные аргументы вы действительно ничего не получаете по сравнению с оригинальной формой с $or
. Это может выглядеть немного чище и" легче вводить", но обычно я не буду" вводить " такую логику в конвейер агрегации напрямую, а скорее генерировать эту часть структуры на основе простого списка в первую очередь:
я.е
var failList = [ 0,100,101,102,103,104,105 ];
var orCondition = failList.map(function(el) {
return { "$eq": [ "$id", el ] }
})
а затем просто используя повторно отображенное содержимое массива в определении конвейера:
{ "$group": {
"_id": "$createdAt",
"count": { "$sum": 1 },
"count_failure": {
"$sum": {
"$cond": [
{ "$or": orCondition },
1,
0
]
}
}
}}
])
независимо от того, как вы смотрите на это, помните это всего лишь структуры данных и у вас есть основные процессы манипулирования. Как внутри обработки трубопровода, так и в самой конструкции трубопровода.
сначала вы должны создать список $id
С помощью $map в проекте, а затем использовать setIsSubset в группы, как показано ниже :
db.collectionName.aggregate([{
"$project": {
"idsArray": {
"$map": {
"input": ["A"],
"as": "el",
"in": {
"$cond": [{
"$eq": ["$$el", "A"]
}, "$id",
null
]
}
}
}
}
}, {
"$group": {
"_id": "$created_at",
"count": {
"$sum": 1
},
"count_failure": {
"$sum": {
"$cond": [{
"$setIsSubset": ["$idsArray", [
0,
100,
101,
102,
103,
104,
105
]]
},
1,
0
]
}
}
}
}])