sql >> Databasteknik >  >> NoSQL >> MongoDB

Flera fält där nycklar i dokument varierar Genomsnittlig aggregation

Konceptöversikt

Vad jag i princip sa i den mycket korta kommentaren är att istället för att utfärda en separat aggregeringsfråga för varje sensor-"nyckel"-namn kan du lägga den i ONE , så länge du beräknar "medelvärdena" korrekt.

Naturligtvis är problemet i din data att "nycklarna" inte finns i alla dokument. Så för att få rätt "genomsnitt" kan vi inte bara använda $avg eftersom det skulle räkna "ALLA" dokument, oavsett om nyckeln fanns eller inte.

Så istället bryter vi upp "matten" och gör en $group för totalt Count och total Sum av varje nyckel först. Detta använder $ifNull för att testa förekomsten av fältet, och även $cond för att alternativa värden för att returnera.

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

$cond operator är en "ternär" operator vilket betyder att det första "om"-villkoret är true , "då" returneras det andra argumentet, "annat" returneras det tredje argumentet.

Så poängen med det ternära i "Count" är att träna:

  • Om fältet finns där, returnera 1 för räkning
  • Annars returnerar den 0 när den inte finns där

Efter $group görs, för att få Average vi använder $divide på de två siffrorna som skapas för varje nyckel inom ett separat $project skede.

Slutresultatet är "genomsnittet" för varje nyckel som du anger, och detta övervägde endast att lägga till värden och siffror för dokument där fältet faktiskt fanns.

Så genom att lägga alla nycklar i en sammanställningssats sparar du mycket tid och resurser vid bearbetning.

Dynamisk generering av pipeline

Så för att göra detta "dynamiskt" i python, börja med listan:

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]

Vilket genererar samma som den fullständiga listan ovan för en given lista med "sensorer".




  1. Node.js &Redis; Väntar på att en loop ska sluta

  2. symfony2 form val och mongodb

  3. grails mongodb anslutning vägrade

  4. Kontrollera om ett fält innehåller en sträng