Resumen del concepto
Lo que básicamente estaba diciendo en el breve comentario es que en cambio para emitir una consulta de agregación separada para cada nombre de "clave" de sensor, puede ponerlo en UNO , siempre que calcule los "promedios" correctamente.
Por supuesto, el problema en sus datos es que las "claves" no están presentes en todos los documentos. Entonces, para obtener el "promedio" correcto, no podemos simplemente usar $avg
ya que contaría "TODOS" los documentos, ya sea que la clave estuviera presente o no.
Entonces, en su lugar, dividimos las "matemáticas" y hacemos un $group
para el Count
total y total Sum
primero de cada tecla. Esto usa $ifNull
para probar la presencia del campo, y también $cond
a valores alternativos para devolver.
.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"
]
}
}}
])
El $cond
operator es un operador "ternario", lo que significa que la primera condición "if" es true
, "entonces" se devuelve el segundo argumento, "si no" se devuelve el tercer argumento.
Entonces el punto del ternario en el "Count"
es resolver:
- Si el campo está allí, devuelva 1 para contar
- De lo contrario, devuelva 0 cuando no esté
Después de $group
hecho, para obtener el Average
usamos $divide
en los dos números producidos para cada clave dentro de un $project
escenario.
El resultado final es el "promedio" de cada clave que proporciona, y esto consideró solo agregar valores y recuentos para documentos donde el campo estaba realmente presente.
Por lo tanto, poner todas las claves en una declaración de agregación le ahorrará mucho tiempo y recursos en el procesamiento.
Generación Dinámica de Pipeline
Entonces, para hacer esto "dinámicamente" en python, comience con la lista:
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]
Lo que genera lo mismo que la lista completa anterior para una lista determinada de "sensores".