有很多文件:
{
"_id" : ObjectId("506ddd1900a47d802702a904"),
"subid" : "s1",
"total" : "300",
"details" :[{
name:"d1", value: "100"
},
{
name:"d2", value: "200"
}]
}
{
"_id" : ObjectId("306fff1900a47d802702567"),
"subid" : "s1",
"total" : "700",
"details" : [{
name:"d1", value: "300"
},
{
name:"d8", value: "400"
}]
}
'详细信息'数组中的元素可能会有所不同。
问题是:如何通过聚合框架和java获得这样的结果?
{
"_id" : "s1",
"total" : "1000",
"details" : [{
name:"d1", value: "400"
},
{
name:"d2", value: "200"
},
{
name:"d8", value: "400"
}]
}
或许我应该在这里使用自定义map-reduce功能?
答案 0 :(得分:2)
这是可以通过聚合实现的,虽然有点迟钝,但让我们通过它:
db.collection.aggregate([
// First Group to get the *master* total for the documents
{"$group": {
"_id": "$subid",
"total": { "$sum": "$total" },
details: { "$push": "$details" }
}},
// Unwind the details
{"$unwind": "$details"},
// Unwind the details "again" since you *pushed* and array onto an array
{"$unwind":"$details"},
// Now sum up the values by each name (keeping levels)
{"$group": {
"_id:" {
"_id": "$_id",
"total": "$total",
"name": "$details.name"
},
"value": {"$sum": "$details.value"}
}},
// Sort the names (because you expect that!)
{"$sort": { "_id.name": 1}},
// Do some initial re-shaping for convenience
{"$project": {
"_id": "$_id._id",
"total": "$_id.total",
"details": { "name": "$_id.name", "value": "$value" }
}},
// Now push everything back into an array form
{"$group": {
"_id": {
"_id": "$_id",
"total": "$total"
},
"details": {"$push": "$details"}
}},
// And finally project nicely
{"$project": {
"_id": "$_id._id",
"total": "$_id.total",
"details": 1
}}
])
因此,如果您之前尝试,您可能错过了执行初始组的概念,以便在total
上获得顶级总和文档中的字段。
不可否认,棘手的位是“让你的头脑”整个双重展开接下来的事情。由于在第一个组中我们将数组推送到另一个数组,我们现在最终得到了这个新的嵌套您需要 展开 两次的结构,以便达到“非规范化”形式。
完成后,您只需$group
到name
字段:
equiv(GROUP BY _id,total,“details.name”)
或多或少那样有一些明智的重塑。然后我要求按name
键排序(因为你以那种方式打印),最后我们$project
进入你想要的实际形式。
所以宾果,我们有你的结果。感谢您提供了一个很酷的问题来展示双重展开的使用。