sql >> Base de Datos >  >> NoSQL >> MongoDB

Múltiples campos donde las claves en el documento varían Agregación promedio

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".