Overzicht van concept
Wat ik eigenlijk zei in de zeer korte opmerking is dat in plaats daarvan om een afzonderlijke aggregatiequery uit te voeren voor elke sensorsleutelnaam, kunt u deze in ONE plaatsen , zolang u de "gemiddelden" correct berekent.
Het probleem in uw gegevens is natuurlijk dat de "sleutels" niet in alle documenten aanwezig zijn. Dus om het juiste "gemiddelde" te krijgen, kunnen we niet zomaar $avg
omdat het "ALLE" documenten zou tellen, ongeacht of de sleutel aanwezig was of niet.
Dus in plaats daarvan splitsen we de "wiskunde" op en doen een $group
voor de totale Count
en totaal Sum
van elke sleutel eerst. Dit gebruikt $ifNull
om te testen op de aanwezigheid van het veld, en ook $cond
naar alternatieve waarden om terug te keren.
.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"
]
}
}}
])
De $cond
operator is een "ternaire" operator, wat betekent dat de eerste "if"-voorwaarde true
is , "dan" wordt het tweede argument geretourneerd, "else" wordt het derde argument geretourneerd.
Dus het punt van de ternaire in de "Count"
is om te trainen:
- Als het veld er is, retourneer dan 1 voor telling
- Anders retourneer 0 als het er niet is
Na de $group
is gedaan, om het Average
. te krijgen we gebruiken $divide
op de twee nummers geproduceerd voor elke sleutel binnen een afzonderlijk $project
podium.
Het eindresultaat is het "gemiddelde" voor elke sleutel die u opgeeft, en dit houdt in dat alleen waarden en tellingen worden toegevoegd voor documenten waarin het veld daadwerkelijk aanwezig was.
Dus als u alle sleutels in één aggregatieverklaring plaatst, bespaart u veel tijd en middelen bij de verwerking.
Dynamisch genereren van pijpleiding
Dus om dit "dynamisch" in python te doen, begin je met de lijst:
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]
Dat genereert hetzelfde als de volledige lijst hierboven voor een bepaalde lijst met "sensoren".