sql >> Database >  >> NoSQL >> MongoDB

Meerdere velden waar de sleutels in het document de gemiddelde aggregatie variëren

Overzicht van concept

Wat ik eigenlijk zei in de zeer korte opmerking is dat in plaats daarvan om een ​​afzonderlijke aggregatiequery uit te voeren voor elke sensorsleutelnaam, kunt u deze in ONE plaatsen , zolang u de "gemiddelden" correct berekent.

Het probleem in uw gegevens is natuurlijk dat de "sleutels" niet in alle documenten aanwezig zijn. Dus om het juiste "gemiddelde" te krijgen, kunnen we niet zomaar $avg omdat het "ALLE" documenten zou tellen, ongeacht of de sleutel aanwezig was of niet.

Dus in plaats daarvan splitsen we de "wiskunde" op en doen een $group voor de totale Count en totaal Sum van elke sleutel eerst. Dit gebruikt $ifNull om te testen op de aanwezigheid van het veld, en ook $cond naar alternatieve waarden om terug te keren.

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

De $cond operator is een "ternaire" operator, wat betekent dat de eerste "if"-voorwaarde true is , "dan" wordt het tweede argument geretourneerd, "else" wordt het derde argument geretourneerd.

Dus het punt van de ternaire in de "Count" is om te trainen:

  • Als het veld er is, retourneer dan 1 voor telling
  • Anders retourneer 0 als het er niet is

Na de $group is gedaan, om het Average . te krijgen we gebruiken $divide op de twee nummers geproduceerd voor elke sleutel binnen een afzonderlijk $project podium.

Het eindresultaat is het "gemiddelde" voor elke sleutel die u opgeeft, en dit houdt in dat alleen waarden en tellingen worden toegevoegd voor documenten waarin het veld daadwerkelijk aanwezig was.

Dus als u alle sleutels in één aggregatieverklaring plaatst, bespaart u veel tijd en middelen bij de verwerking.

Dynamisch genereren van pijpleiding

Dus om dit "dynamisch" in python te doen, begin je met de lijst:

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]

Dat genereert hetzelfde als de volledige lijst hierboven voor een bepaalde lijst met "sensoren".




  1. Hoe gebruik je $arrayElemAt en verwijder je velden uit dat element in MongoDB $projection?

  2. Hoe een reeks hashes op te slaan in redis

  3. Mongodb shell mongo:normaal is slechts één gebruik van elk socketadres (protocol/netwerkadres/poort) toegestaan. voor stopcontact:0.0.0.0:27017

  4. Mongoose Unieke index werkt niet!