有许多文件:
{
"_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"
}]
}
“details”数组中的元素可能会有所不同。
问题是:如何用聚合框架和Java获得这样的结果?
{
"_id" : "s1",
"total" : "1000",
"details" : [{
name:"d1", value: "400"
},
{
name:"d2", value: "200"
},
{
name:"d8", value: "400"
}]
}
或者我应该在这里使用自定义的map reduce函数?
最佳答案
这是可以通过聚合来实现的,虽然有点迟钝,但是让我们通过它:
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(按ID分组,总计,“details.name”)
所以或多或少的像这样,有一些合理的重新塑造。然后我要求按
name
键进行排序(因为您是这样打印的),最后我们将$project
按您想要的实际形式进行排序。对了,我们有你的结果。谢谢你问了个很酷的问题,让我们来看看双倍放松法的使用。
关于mongodb - Mongodb和聚合框架。对数组的元素求和以及文档的元素,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22018494/