それ 大変でした!
まず、必要な解決策:
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"
}
]
}
]
}
そして今、いくつかの説明のために:
ここでの主要な問題の1つは、各受信ドキュメントが2つのの一部である必要があることです。 異なる合計。リテラル配列["age", "childs"]
を追加することでそれを解決しました ドキュメントに追加し、その配列でそれらを巻き戻します。そうすれば、各ドキュメントが2回表示されます。 後の段階で。
それが終わったら、処理を簡単にするために、データ表現を{ data: "age", value: "40" }
のようなはるかに管理しやすいものに変更します。
次の手順は、データ集約自体を実行します。 3番目までの$project
値フィールドを対応するage
にマップするステップ またはchilds
フィールド。
最後の2つの手順では、2つのドキュメントを1つにまとめて、不要な_id
を削除します。 フィールド。
Pfff!