Konzeptskizze
Was ich in dem sehr kurzen Kommentar im Grunde gesagt habe, ist das stattdessen zum Ausgeben einer separaten Aggregationsabfrage für jeden Sensor-"Schlüssel"-Namen können Sie ihn in ONE einfügen , solange Sie die "Durchschnitte" richtig berechnen.
Das Problem in Ihren Daten ist natürlich, dass die "Schlüssel" nicht in allen Dokumenten vorhanden sind. Um also den korrekten „Durchschnitt“ zu erhalten, können wir nicht einfach $avg
da es "ALLE" Dokumente zählen würde, egal ob der Schlüssel vorhanden war oder nicht.
Stattdessen brechen wir die „Mathematik“ auf und machen einen $group
für die Gesamt-Count
und Gesamt Sum
jeder Taste zuerst. Dies verwendet $ifNull
um das Vorhandensein des Felds zu testen, und auch $cond
zu alternativen zurückzugebenden Werten.
.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"
]
}
}}
])
Der $cond
operator ist ein "ternärer" Operator, was bedeutet, dass die erste "if"-Bedingung true
ist , "then" wird das zweite Argument zurückgegeben, "else" wird das dritte Argument zurückgegeben.
Also der Punkt des Ternären im "Count"
ist zu erarbeiten:
- Wenn das Feld vorhanden ist, geben Sie 1 für count zurück
- Gib andernfalls 0 zurück, wenn es nicht vorhanden ist
Nach dem $group
getan, um den Average
zu erhalten wir verwenden $divide
auf den zwei Zahlen, die für jeden Schlüssel innerhalb eines separaten $project
Stufe.
Das Endergebnis ist der "Durchschnitt" für jeden Schlüssel, den Sie angeben, und dabei wurden nur Werte und Zählungen für Dokumente hinzugefügt, in denen das Feld tatsächlich vorhanden war.
Wenn Sie also alle Schlüssel in eine Aggregationsanweisung einfügen, sparen Sie viel Zeit und Ressourcen bei der Verarbeitung.
Dynamische Generierung der Pipeline
Um dies "dynamisch" in Python zu tun, beginnen Sie mit der Liste:
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]
Das erzeugt dasselbe wie die vollständige Liste oben für eine gegebene Liste von "Sensoren".