MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Как да групирате по различни полета

Това беше трудно!

Първо, чистото решение:

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

Продуциране:

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

А сега, за някои обяснения:

Един от основните проблеми тук е, че всеки входящ документ трябва да бъде част от два различни суми. Реших това, като добавих литерален масив ["age", "childs"] към вашите документи и след това да ги развиете от този масив. По този начин всеки документ ще бъде представен два пъти в по-късен етап.

След като това стане, за да улесня обработката, променям представянето на данните на нещо много по-управляемо като { data: "age", value: "40" }

Следващите стъпки ще извършат самото агрегиране на данни. До третия $project стъпка, която ще съпостави полетата със стойност към съответната age или childs поле.

Последните две стъпки просто ще обвият двата документа в един, премахвайки ненужния _id поле.

Пффф!




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Изтегляне на MongoDB Java

  2. Как MongoDB прилага своите пространствени индекси?

  3. Как да управлявате шаблони за конфигурация за вашите бази данни с ClusterControl

  4. Как да получа достъп до MongoDB на Meteor от друг клиент, докато Meteor работи?

  5. MongoDb:Как да вмъкна допълнителен обект в колекция от обекти?