Очертание на концепцията
Това, което всъщност казах в много краткия коментар, е, че вместо това за издаване на отделна заявка за агрегиране за всяко име на "ключ" на сензора, можете да го поставите в ONE , стига да изчислите правилно "средните стойности".
Разбира се, проблемът във вашите данни е, че "ключовете" не присъстват във всички документи. Така че, за да получим правилната „средна стойност“, не можем просто да използваме $avg
тъй като ще преброи "ВСИЧКИ" документи, независимо дали ключът присъства или не.
Затова вместо това разбиваме „математиката“ и правим $group
за общия Count
и обща Sum
на всеки ключ първо. Това използва $ifNull
за тестване за наличие на полето, а също и $cond
за редуване на стойности за връщане.
.aggregate([
{ "$match": {
"$or": [
{ "Technique-Electrique_VMC Aldes_Power4[W]": { "$exists": True } },
{ "Technique-Electrique_VMC Unelvent_Power5[W]": { "$exists": True } }
]
}}
{ "$group":{
"_id":{
"year":{ "$year":"$timestamp" },
"month":{ "$month":"$timestamp" }
},
"Technique-Electrique_VMC Aldes_Power4[W]-Sum": {
"$sum": {
"$ifNull": [ "$Technique-Electrique_VMC Aldes_Power4[W]", 0 ]
}
},
"Technique-Electrique_VMC Aldes_Power4[W]-Count": {
"$sum": {
"$cond": [
{ "$ifNull": [ "$Technique-Electrique_VMC Aldes_Power4[W]", false ] },
1,
0
]
}
},
"Technique-Electrique_VMC Unelvent_Power5[W]-Sum": {
"$sum": {
"$ifNull": [ "$Technique-Electrique_VMC Unelvent_Power5[W]", 0 ]
}
},
"Technique-Electrique_VMC Unelvent_Power5[W]-Count": {
"$sum": {
"$cond": [
{ "$ifNull": [ "$Technique-Electrique_VMC Unelvent_Power5[W]", false ] },
1,
0
]
}
}
}},
{ "$project": {
"Technique-Electrique_VMC Aldes_Power4[W]-Avg": {
"$divide": [
"$Technique-Electrique_VMC Aldes_Power4[W]-Sum",
"$Technique-Electrique_VMC Aldes_Power4[W]-Count"
]
},
"Technique-Electrique_VMC Unelvent_Power5[W]-Avg": {
"$divide": [
"Technique-Electrique_VMC Unelvent_Power5[W]-Sum",
"Technique-Electrique_VMC Unelvent_Power5[W]-Count"
]
}
}}
])
$cond
е "троичен" оператор, което означава, че първото условие "if" е true
, "then" се връща вторият аргумент, "else" се връща третият аргумент.
Така че точката на троичния елемент в "Count"
е да тренирате:
- Ако полето е там, върнете 1 за броя
- В противен случай върнете 0, когато не е там
След $group
е направено, за да получите Average
използваме $divide
върху двете числа, произведени за всеки ключ в отделен $project
етап.
Крайният резултат е „средната стойност“ за всеки ключ, който предоставяте, и това се счита само за добавяне на стойности и броене за документи, където полето действително присъства.
Така че поставянето на всички ключове в един оператор за агрегиране ще ви спести много време и ресурси за обработка.
Динамично генериране на конвейер
Така че, за да направите това „динамично“ в python, започнете със списъка:
sensors = ["Technique-Electrique_VMC Aldes_Power4[W]", "Technique-Electrique_VMC Unelvent_Power5[W]"]
match = { '$match': { '$or': map(lambda x: { x: { '$exists': True } },sensors) } }
group = { '$group': {
'_id': {
'year': { '$year': '$timestamp' },
'month': { '$month':'$timestamp' }
}
}}
project = { '$project': { } }
for k in sensors:
group['$group'][k + '-Sum'] = {
'$sum': { '$ifNull': [ '$' + k, 0 ] }
}
group['$group'][k + '-Count'] = {
'$sum': { '$cond': [ { '$ifNull': [ '$' + k, False ] }, 1, 0 ] }
}
project['$project'][k + '-Avg'] = {
'$divide': [ '$' + k + '-Sum', '$' + k + '-Count' ]
}
pipeline = [match,group,project]
Което генерира същото като пълния списък по-горе за даден списък от „сензори“.