MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Campi multipli in cui le chiavi nel documento variano nell'aggregazione media

Schema concettuale

Quello che stavo sostanzialmente dicendo nel brevissimo commento è che invece per eseguire una query di aggregazione separata per ogni nome di "chiave" del sensore, puoi inserirlo in UNO , a patto di calcolare correttamente le "medie".

Ovviamente il problema nei tuoi dati è che le "chiavi" non sono presenti in tutti i documenti. Quindi, per ottenere la "media" corretta, non possiamo semplicemente usare $avg poiché conterebbe "TUTTI" i documenti, indipendentemente dal fatto che la chiave fosse presente o meno.

Quindi, invece, interrompiamo la "matematica" e facciamo un $group per il Count totale e totale Sum prima di ogni chiave. Questo utilizza $ifNull per verificare la presenza del campo, e anche $cond per alternare i valori da restituire.

.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"
      ]
    }
  }}
])

Il $cond operatore è un operatore "ternario" che significa dove la prima condizione "se" è true , "quindi" viene restituito il secondo argomento, "else" viene restituito il terzo argomento.

Quindi il punto del ternario nel "Count" è da risolvere:

  • Se il campo è presente, restituisci 1 per il conteggio
  • Altrimenti restituisci 0 quando non è presente

Dopo il $group è fatto, per ottenere la Average usiamo $divide sui due numeri prodotti per ciascuna chiave all'interno di un separato $project fase.

Il risultato finale è la "media" per ogni chiave che fornisci, e questo ha considerato solo l'aggiunta di valori e conteggi per i documenti in cui il campo era effettivamente presente.

Quindi inserire tutte le chiavi in ​​un'unica istruzione di aggregazione ti farà risparmiare molto tempo e risorse nell'elaborazione.

Generazione dinamica di pipeline

Quindi, per farlo "dinamicamente" in Python, inizia con l'elenco:

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]

Che genera lo stesso elenco completo sopra per un determinato elenco di "sensori".