2017-02-23 3 views
1

Guten Tag produziert Array,Iterieren durch alle von MongoDB Aggregationsanfrage

ich mit Aggregationsanfragen in MongoDB 3.4 eine wirklich harte Zeit arbeiten habe. Ich habe ein Problem, das mich bittet zu tun, die Ergebnisse meiner Aggregations Abfrage in ein leeres Array schieben genannt categories, die ich erfolgreich mit diesem Code zu tun in der Lage:

var categories = []; 

    database.collection("item").aggregate([{ 
     $group : { 
      _id : "$category", 
      num : {$sum : 1} 
     }}, 
     {$sort:{_id:1}}]).toArray(function(err, data){ 

      categories.push(...data); 
      callback(categories); 
      console.log(categories); 
     }) 

    } 

categories wie folgt aussieht:

[ { _id: 'Apparel', num: 6 }, 
{ _id: 'Books', num: 3 }, 
{ _id: 'Electronics', num: 3 }, 
{ _id: 'Kitchen', num: 3 }, 
{ _id: 'Office', num: 2 }, 
{ _id: 'Stickers', num: 2 }, 
{ _id: 'Swag', num: 2 }, 
{ _id: 'Umbrellas', num: 2 } ] 

Next ich habe folgende Aufgabe:

 In addition to the categories created by your aggregation query, 
    include a document for category "All" in the array of categories 
    passed to the callback. The "All" category should contain the total 
    number of items across all categories as its value for "num". The 
    most efficient way to calculate this value is to iterate through 
    the array of categories produced by your aggregation query, summing   
    counts of items in each category. 

Das Problem ist, dass es scheint, wie in meiner .toArray() Methode der data Parameter manchmal wie ein Array und manchmal nicht funktioniert. Zum Beispiel, wenn ich vielleicht nur den Wert des num-Schlüssels zum categories-Array hinzufügen wollte, so: categories.push(...data["num"]) bekomme ich einen Fehler unter der Angabe undefined is not iterable.

Da ich nicht über jeden Schlüssel data.num iterieren kann, kann ich seinen Wert nicht extrahieren und es zu einer laufenden Summe aller Werte data.num hinzufügen.

Was verstehe ich nicht, was hier vor sich geht?

Antwort

3

Sie müssen keine Anwendungslogik verwenden, um Daten zu gruppieren. Die mongoDB-Aggregation wird für diese Aufgabe erstellt. In einem anderen $group auf Ihre Frage mit einem neuen Feld All dass $sum Ihre $num Feld und $push alle Dokumente zu einem neuen Feld categories genannt:

{ 
    "_id": 1, 
    "All": 23, 
    "categories": [{ 
     "_id": "Swag", 
     "num": 2 
    }, { 
     "_id": "Office", 
     "num": 2 
    }, { 
     "_id": "Stickers", 
     "num": 2 
    }, { 
     "_id": "Apparel", 
     "num": 6 
    }, { 
     "_id": "Umbrellas", 
     "num": 2 
    }, { 
     "_id": "Kitchen", 
     "num": 3 
    }, { 
     "_id": "Books", 
     "num": 3 
    }, { 
     "_id": "Electronics", 
     "num": 3 
    }] 
} 

Für die Ausgabe raubend data:

db.item.aggregate([{ 
    $group: { 
     _id: "$category", 
     num: { $sum: 1 } 
    } 
}, { $sort: { _id: 1 } }, { 
    $group: { 
     _id: 1, 
     All: { $sum: "$num" }, 
     categories: { 
      $push: { 
       _id: "$_id", 
       num: "$num" 
      } 
     } 
    } 
}]) 

Es gibt ist ein array, Zugriff auf das erste Element Verwendung data[0]:

var categories = []; 

database.collection("item").aggregate([{ 
    $group: { 
     _id: "$category", 
     num: { $sum: 1 } 
    } 
}, { $sort: { _id: 1 } }, { 
    $group: { 
     _id: 1, 
     All: { $sum: "$num" }, 
     categories: { 
      $push: { 
       _id: "$_id", 
       num: "$num" 
      } 
     } 
    } 
}]).toArray(function(err, data) { 

    var totalCount = data[0]["All"]; 
    console.log("total count is " + totalCount); 

    categories = data[0]["categories"]; 

    for (var i = 0; i < categories.length; i++) { 
     console.log("category : " + categories[i]._id + " | count : " + categories[i].num); 
    } 
}) 
+0

Ihre Lösung ist nah an dem, was ich suchte und ich schätze Ihre Antwort. Ich denke, insgesamt nach Ihrem Input habe ich ein besseres Verständnis dafür, womit ich es zu tun habe. Das einzige, was mir nicht klar war, war die Notwendigkeit, den neuen '{category:" All} '-Dokumentteil des' data'-Arrays zu erstellen. Ich werde meine Antwort unter Ihre schreiben, damit Sie sehen können, was ich wollte. – m00saca

0

Was ich erreichen wollte, schob oder unshifting wie wir in einem Moment ein Objekt, das so aussah in meine categories Array sehen werden:

var allCategory = { 
     _id: "All", 
     num: [sum of all data.num values] 
} 

Ich landete Messing mit .reduce() Methode, und es verwendet auf dem categories Array. Ich habe das Glück durch einige console.log -ing und endete diese machen:

var categories = []; 

    database.collection("item").aggregate([{ 
     $group : { 
      _id : "$category", 
      num : {$sum : 1} 
     }}, 
     {$sort:{_id:1}}]).toArray(function(err, data){ 
      categories.push(...data); 
      var sum = categories.reduce(function(acc, val){ 
       // console.log(acc, val["num"]) 
       return acc + val["num"] 
      },0); 

      var allCategory = { 
       _id: "All", 
       num: sum 
      } 
      categories.unshift(allCategory) 
      callback(categories); 
     }) 

Zuerst habe ich einen Spread-Operator verwenden alle Objekte aus data in categories zu schieben. Dann deklarieren Sie sum, die .reduce() auf categories läuft, die die Ansammlung von val["num"] zurückbringt, die wirklich data.num ist (Konsolenprotokoll ist Leben). Ich erstelle das allCategory Dokument/Objekt, dann benutze .unshift, um es am Anfang meines categories Arrays zu platzieren (diese Platzierung war eine Voraussetzung), dann benutze meinen Rückruf.

Ich denke, es ist ein hacky Weg, um mein Ziel zu erreichen, und ich musste einige Versuch und Irrtum über die richtige Reihenfolge der Methoden und Variablen in meinem .toArray() gehen. Aber es hat funktioniert und ich habe etwas gelernt. Danke für die Hilfe @Bertrand Martel.

Verwandte Themen