2016-05-31 15 views
1

Hey Leute, ich bin wirklich neu, wenn es um Aggregation geht, bitte helft mir dabei.MongoDB Aggregation AVG()

Lassen Sie uns sagen, dass ich mehrere Dokumente haben (über die Zeit) wie folgt aus:

{ 
    "_id": ObjectId("574d6175da461e77030041b7"), 
    "hostname": "VPS", 
    "timestamp": NumberLong(1460040691), 
    "cpuCores": NumberLong(2), 
    "cpuList": [ 
    { 
     "name": "cpu1", 
     "load": 3.4 
    }, 
    { 
     "name": "cpu2", 
     "load": 0.7 
    } 
    ] 
}, 
{ 
    "_id": ObjectId("574d6175da461e77030041b7"), 
    "hostname": "VPS", 
    "timestamp": NumberLong(1460040700), 
    "cpuCores": NumberLong(2), 
    "cpuList": [ 
    { 
     "name": "cpu1", 
     "load": 0.4 
    }, 
    { 
     "name": "cpu2", 
     "load": 6.7 
    } 
    ] 
}, 
{ 
    "_id": ObjectId("574d6175da461e77030041b7"), 
    "hostname": "VPS", 
    "timestamp": NumberLong(1460041000), 
    "cpuCores": NumberLong(2), 
    "cpuList": [ 
    { 
     "name": "cpu1", 
     "load": 25.4 
    }, 
    { 
     "name": "cpu2", 
     "load": 1.7 
    } 
    ] 
} 

Ich mag würde die durchschnittliche CPU-Auslastung über X Zeit bekommen. Wobei X gleich 300 Sekunden ist.

So mit dem obigen Beispiel würde man ein Resultset erhalten, die wie folgt aussieht:

{ 
    "avgCPULoad": "2.8", 
    "timestamp": NumberLong(1460040700) 
}, 
{ 
    "avgCPULoad": "13.55", 
    "timestamp": NumberLong(1460041000) 
} 

avgCpuLoad wird wie folgt berechnet:

  1. greifen alle Dokumente innerhalb von 300 Sekunden von eachother
  2. berechnen Durchschnitt:
    1. (((3.4+0.7)/2)+((0.4+6.7)/2))/2 = 2.8
    2. ((25.4+1.7)/2) = 13.55
  3. hinzufügen Letzten Zeitstempel aus den ausgewählten Dokumenten.

Ich weiß, wie ich jedes Dokument für jede x Zeit bekomme. Das ist so gemacht:

db.Pizza.aggregate(
[ 
    { 
     $group: 
     { 
      _id: 
      { 
       $subtract: [ 
        '$timestamp', 
        { 
         $mod: ['$timestamp', 300] 
        } 
       ] 
      }, 
      'timestamp': {$last:'$timestamp'} 
     }, 
    { 
     $project: {_id: 0, timestamp:'$timestamp'} 
    } 
]) 

Aber wie würde man die Durchschnittswerte wie oben berechnet bekommen? Ich habe ein wenig mit $unwind versucht, aber nicht die Ergebnisse, die ich gerne ..

+0

Betrachten Sie Ihr Schema aufgeteilt bekommen abgeleiteter Wechsel haben eingebettete Dokumente mit konsistenten Schlüssel-Wert-Dokumenten für Ihr '" cpuList "' Feld zB '" cpuList ": [{name:" cpu1 ", laden: 3.4}, {name:" cpu2 ", laden: 0.7}]'. Sie müssen auch die "load" -Werte in numerische umwandeln, damit die Aggregations-Akkumulator-Operatoren wie '$ avg' effektiv sein können. – chridam

+0

Der Grund, warum ich meine Load-Eigenschaften-Strings erstellt habe, war, dass, wann immer ich es zu einem numerischen Wert mache, ich mit dem Präzisions-Float ein Chaos bekommen würde. Zum Beispiel wurde in PHP ein float um 2 Dezimalstellen gerundet. Wann immer ich es in Mongo setzte, bekam es statt 2 Dezimalzahlen wie 10 mehr oder etwas mit einem wirklich kleinen Offset – Baklap4

+0

@chridam Okay, ich habe mein Schema auf das geändert, was Sie vorgeschlagen haben. Wie würde man die Abfrage machen, um den Durchschnitt zu berechnen? – Baklap4

Antwort

1

Sie müssen die folgende Aggregationsoperation ausführen, um das gewünschte Ergebnis zu erhalten:

db.collection.aggregate([ 
    { "$unwind": "$cpuList" }, 
    { 
     "$group": { 
      "_id": {     
       "interval": { 
        "$subtract": [ 
         "$timestamp",       
         { "$mod": [ "$timestamp", 60 * 5 ] } 
        ] 
       } 
      },    
      "avgCPULoad": { "$avg": "$cpuList.load" }, 
      "timestamp": { "$max": "$timestamp" } 
     } 
    }, 
    { 
     "$project": { "_id": 0, "avgCPULoad": 1, "timestamp": 1 } 
    } 
]) 

Die oben genannten Gruppen die abgeflachte Dokumente von einem 5-Minuten-Intervall (in Sekunden dargestellt); der Intervallschlüssel wird berechnet, indem den Zeitstempel in Sekunden vom Rest Sie, wenn der tatsächliche Zeitstempel wird von dem 5 Minuten-Intervall (in Sekunden)

Beispielausgabe

/* 1 */ 
{ 
    "avgCPULoad" : 13.55, 
    "timestamp" : NumberLong(1460041000) 
} 

/* 2 */ 
{ 
    "avgCPULoad" : 2.8, 
    "timestamp" : NumberLong(1460040700) 
} 
+1

Der Zeitstempel ist in Sekunden nicht in Millisekunden – Baklap4

+0

@ Baklap4 Sie haben Recht, mein Schlechter. Ich habe die Antwort aktualisiert, um die Sekunden statt der Millisekunden anzuzeigen. – chridam

+0

Jede Möglichkeit innerhalb von Mongo zu runden? – Baklap4

1

Die Lösung für dieses ist die Verwendung von Abwickeln auf dem Array (Cpulist). Ich habe ein Beispiel Abfrage für Sie gemacht:

db.CpuInfo.aggregate([ 
    { 
     $unwind: '$cpuList' 
    }, 
    { 
     $group: { 
      _id:{ 
       $subtract:[ 
        '$timestamp', 
        {$mod: ['$timestamp', 300]} 
       ] 
      }, 
      'timestamp':{$last:'$timestamp'}, 
      'cpuList':{$avg:'$cpuList.load'} 
     } 
    } 
])