MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

So gruppieren Sie nach verschiedenen Feldern

Das war eine harte Nuss!

Zuerst die nackte Lösung:

db.test.aggregate([
 { "$match": { "user": "Hans" } },
 // duplicate each document: one for "age", the other for "childs"
 { $project: { age: "$age", childs: "$childs",
               data: {$literal: ["age", "childs"]}}},
 { $unwind: "$data" },
 // pivot data to something like { data: "age", value: "40" }
 { $project: { data: "$data",
               value: {$cond: [{$eq: ["$data", "age"]},
                               "$age", 
                               "$childs"]} }},
 // Group by data type, and count
 { $group: { _id: {data: "$data", value: "$value" }, 
             count: { $sum: 1 }, 
             value: {$first: "$value"} }},
 // aggregate values in an array for each independant (type,value) pair
 { $group: { _id: "$_id.data", values: { $push: { count: "$count", value: "$value" }} }} ,
 // project value to the correctly name field
 { $project: { result: {$cond: [{$eq: ["$_id", "age"]},
                               {age: "$values" }, 
                               {childs: "$values"}]} }},
 // group all data in the result array, and remove unneeded `_id` field 
 { $group: { _id: null, result: { $push: "$result" }}},
 { $project: { _id: 0, result: 1}}
])

Produzieren:

{
    "result" : [
        {
            "age" : [
                {
                    "count" : 3,
                    "value" : "40"
                },
                {
                    "count" : 1,
                    "value" : "50"
                }
            ]
        },
        {
            "childs" : [
                {
                    "count" : 1,
                    "value" : "1"
                },
                {
                    "count" : 3,
                    "value" : "2"
                }
            ]
        }
    ]
}

Und nun zu einigen Erklärungen:

Eines der Hauptprobleme dabei ist, dass jedes eingehende Dokument Teil von zwei sein muss unterschiedliche Summen. Ich habe das gelöst, indem ich ein wörtliches Array ["age", "childs"] hinzugefügt habe zu Ihren Dokumenten, und wickeln Sie sie dann durch dieses Array ab. Auf diese Weise wird jedes Dokument zweimal präsentiert in der späteren Phase.

Sobald dies erledigt ist, ändere ich zur Vereinfachung der Verarbeitung die Datendarstellung in etwas viel Verwaltbareres wie { data: "age", value: "40" }

Die folgenden Schritte führen die Datenaggregation per se durch. Bis zum dritten $project Schritt, der die Wertefelder dem entsprechenden age zuordnet oder childs Feld.

Die letzten beiden Schritte packen die beiden Dokumente einfach in ein Dokument und entfernen die nicht benötigte _id Feld.

Pfff!