2016-06-21 15 views
1

Zum Beispiel habe ich Sammlung folgende:Get Anzahl der "loglevel" für jeden "name"

db.names.find ({})

{ "_id" : ObjectId("5768d9b4bc6f464899594570"), "name" : "t1", "loglevel" : "ERROR" } 

{ "_id" : ObjectId("5768d9d5bc6f464899594571"), "name" : "t1", "loglevel" : "ERROR" } 

{ "_id" : ObjectId("5768d9dcbc6f464899594572"), "name" : "t1", "loglevel" : "WARNING" } 

{ "_id" : ObjectId("5768d9dfbc6f464899594573"), "name" : "t1", "loglevel" : "WARNING" } 

{ "_id" : ObjectId("5768d9e0bc6f464899594574"), "name" : "t1", "loglevel" : "WARNING" } 

{ "_id" : ObjectId("5768d9e7bc6f464899594575"), "name" : "t1", "loglevel" : "INFO" } 

{ "_id" : ObjectId("5768d9f3bc6f464899594576"), "name" : "t2", "loglevel" : "INFO" } 

{ "_id" : ObjectId("5768d9f9bc6f464899594577"), "name" : "t2", "loglevel" : "ERROR" } 

{ "_id" : ObjectId("5768da19bc6f464899594578"), "name" : "t2", "loglevel" : "ERROR" } 

{ "_id" : ObjectId("5768da1abc6f464899594579"), "name" : "t2", "loglevel" : "ERROR" } 

{ "_id" : ObjectId("5768da1bbc6f46489959457a"), "name" : "t2", "loglevel" : "ERROR" } 

{ "_id" : ObjectId("5768e247bc6f46489959457b"), "name" : "t3", "loglevel" : "INFO" } 

Ich habe versucht, aber ich denke, es sollte eine bessere Lösung sein

db.names.aggregate(
    {$group: { 
     _id: "$name", 
     error: {$sum: {$cond: {if: {$eq: ['$loglevel', 'ERROR']}, then: {$sum: 1}, else: {$sum: 0}}}}, 
     warning: {$sum: {$cond: {if: {$eq: ['$loglevel', 'WARNING']}, then: {$sum: 1}, else: {$sum: 0}}}}, 
     info: {$sum: {$cond: {if: {$eq: ['$loglevel', 'INFO']}, then: {$sum: 1}, else: {$sum: 0}}}} 
    }} 
) 

Antwort

3

Entfernen Sie die { "$sum": 1 } und { "$sum": 0 } Ausdrücke in if/else bedingte Blöcke, ersetzen sie mit den Werten 1 und 0 (jeweils für jeden bedingten Block).

sollte die End-Pipeline wie folgt aussehen, die andere $cond Syntax, die die if/else Blöcke weglässt:

db.names.aggregate([ 
    { 
     "$group": { 
      "_id": "$name", 
      "error": { 
       "$sum": { 
        "$cond": [ { "$eq": [ "$loglevel", "ERROR" ] }, 1, 0] 
       } 
      }, 
      "warning":{ 
       "$sum": { 
        "$cond": [ { "$eq": [ "$loglevel", "WARNING" ] }, 1, 0 ] 
       } 
      }, 
      "info": { 
       "$sum": { 
        "$cond": [ { "$eq": [ "$loglevel", "INFO" ] }, 1, 0 ] 
       } 
      } 
     } 
    } 
]) 

oder dynamisch die Pipeline erstellen, eine Reihe von möglichen Status gegeben:

var statuses = ["ERROR", "WARNING", "INFO"], 
    groupOperator = { "$group": { "_id": "$name" } }; 

statuses.forEach(function (status){ 
    groupOperator["$group"][status.toLowerCase()] = { 
     "$sum": { 
      "$cond": [ { "$eq": [ "$loglevel", status ] }, 1, 0] 
     } 
    } 
}); 

db.names.aggregate([groupOperator]); 

Ausgabe

/* 1 */ 
{ 
    "_id" : "t1", 
    "error" : 2, 
    "warning" : 3, 
    "info" : 1 
} 

/* 2 */ 
{ 
    "_id" : "t2", 
    "error" : 4, 
    "warning" : 0, 
    "info" : 1 
} 

/* 3 */ 
{ 
    "_id" : "t3", 
    "error" : 0, 
    "warning" : 0, 
    "info" : 1 
} 
+0

Guter Punkt über If/Else blockiert, aber ich suche immer noch DRY Lösung (nicht Loglevel Block duplizieren) – madzohan

+0

@madzohan Aktualisiert meine Antwort, um den DRY-Ansatz zu enthalten. – chridam

+0

schön! könntest du mir auch sagen, welcher Weg besser wäre (Leistung, etc) - Logik wie Gruppierung in mongodb beibehalten oder sie in Programmiersprache wie Python verschieben? – madzohan

1

Wenn ich richtig verstehe (else kann auch weggelassen werden), Sie wollen die Summe von logle vels gegen jeden Namen. sollte das nicht helfen?

db.names.aggregate([{$group:{_id:{name:"$name",loglevel:"$loglevel"},sum:{$sum:1}}}]) 
+0

yep Ich habe diese früher versucht, aber ich brauche es in gruppierten Weise durch '$ name' mit allen Loglevel – madzohan

+0

rechts kommentiert. habe gerade @ Chridams Antwort gesehen. denke, das ist was du suchst. – KaSh