MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Champs multiples où les clés du document varient Agrégation moyenne

Aperçu du concept

Ce que je disais essentiellement dans le très bref commentaire, c'est que à la place pour émettre une requête d'agrégation distincte pour chaque nom de "clé" de capteur, vous pouvez la mettre dans UNE , tant que vous calculez correctement les "moyennes".

Bien sûr, le problème dans vos données est que les "clés" ne sont pas présentes dans tous les documents. Donc, pour obtenir la "moyenne" correcte, nous ne pouvons pas simplement utiliser $avg puisqu'il compterait "TOUS" les documents, que la clé soit présente ou non.

Donc, à la place, nous décomposons les "maths" et faisons un $group pour le Count total et la Sum totale de chaque touche en premier. Cela utilise $ifNull pour tester la présence du champ, et aussi $cond pour alterner les valeurs à renvoyer.

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

Le $cond L'opérateur est un opérateur "ternaire", ce qui signifie que la première condition "if" est true , "then" le deuxième argument est renvoyé, "else" le troisième argument est renvoyé.

Donc le point du ternaire dans le "Count" est de travailler :

  • Si le champ est là, renvoyez 1 pour le compte
  • Sinon, renvoyez 0 lorsqu'il n'est pas là

Après le $group est fait, afin d'obtenir la Average nous utilisons $divide sur les deux numéros produits pour chaque clé dans un $project scène.

Le résultat final est la "moyenne" pour chaque clé que vous fournissez, et cela ne prend en compte que l'ajout de valeurs et de comptes pour les documents où le champ était réellement présent.

Ainsi, mettre toutes les clés dans une seule instruction d'agrégation vous fera économiser beaucoup de temps et de ressources lors du traitement.

Génération dynamique de pipeline

Donc pour faire ça "dynamiquement" en python, commencez par la liste :

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]

Ce qui génère la même chose que la liste complète ci-dessus pour une liste donnée de "capteurs".