MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Jak grupować według różnych dziedzin

To był trudny!

Po pierwsze, samo rozwiązanie:

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

Produkcja:

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

A teraz kilka wyjaśnień:

Jednym z głównych problemów jest to, że każdy przychodzący dokument musi być częścią dwóch różne sumy. Rozwiązałem to, dodając tablicę literałów ["age", "childs"] do dokumentów, a następnie rozwijanie ich przez tę tablicę. W ten sposób każdy dokument będzie prezentowany dwa razy na późniejszym etapie.

Po wykonaniu tej czynności, aby ułatwić przetwarzanie, zmieniam reprezentację danych na coś znacznie łatwiejszego w zarządzaniu, na przykład { data: "age", value: "40" }

Poniższe kroki wykonają agregację danych per se. Do trzeciego $project krok, który zmapuje pola wartości na odpowiedni age lub childs pole.

Ostatnie dwa kroki po prostu zawiną dwa dokumenty w jeden, usuwając niepotrzebny _id pole.

Pfff!




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. 7 sposobów liczenia dokumentów w MongoDB

  2. Zapytanie MongoDB $in z tablicą wyrażeń regularnych elementu

  3. sortuj kolekcję mongo na podstawie wyniku dokumentów podrzędnych

  4. Nie można używać Linq z zagnieżdżoną klasą List<> w MongoDb C#

  5. Łatwy sposób na zwiększenie wersji dokumentów Mongoose dla wszelkich zapytań dotyczących aktualizacji?