Konceptöversikt
Vad jag i princip sa i den mycket korta kommentaren är att istället för att utfärda en separat aggregeringsfråga för varje sensor-"nyckel"-namn kan du lägga den i ONE , så länge du beräknar "medelvärdena" korrekt.
Naturligtvis är problemet i din data att "nycklarna" inte finns i alla dokument. Så för att få rätt "genomsnitt" kan vi inte bara använda $avg
eftersom det skulle räkna "ALLA" dokument, oavsett om nyckeln fanns eller inte.
Så istället bryter vi upp "matten" och gör en $group
för totalt Count
och total Sum
av varje nyckel först. Detta använder $ifNull
för att testa förekomsten av fältet, och även $cond
för att alternativa värden för att returnera.
.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
operator är en "ternär" operator vilket betyder att det första "om"-villkoret är true
, "då" returneras det andra argumentet, "annat" returneras det tredje argumentet.
Så poängen med det ternära i "Count"
är att träna:
- Om fältet finns där, returnera 1 för räkning
- Annars returnerar den 0 när den inte finns där
Efter $group
görs, för att få Average
vi använder $divide
på de två siffrorna som skapas för varje nyckel inom ett separat $project
skede.
Slutresultatet är "genomsnittet" för varje nyckel som du anger, och detta övervägde endast att lägga till värden och siffror för dokument där fältet faktiskt fanns.
Så genom att lägga alla nycklar i en sammanställningssats sparar du mycket tid och resurser vid bearbetning.
Dynamisk generering av pipeline
Så för att göra detta "dynamiskt" i python, börja med listan:
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]
Vilket genererar samma som den fullständiga listan ovan för en given lista med "sensorer".