有许多文件:

{
        "_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字段执行初始组以获得顶级和。
诚然,棘手的一点是“让你的头周围”的整个双重放松的事情,接下来。因为在第一组中,我们将一个数组推送到另一个数组中,然后我们现在得到了这个新的嵌套结构,您需要将其展开两次才能得到“非规范化”形式。
完成后,您只需$groupname字段:
equiv(按ID分组,总计,“details.name”)
所以或多或少的像这样,有一些合理的重新塑造。然后我要求按name键进行排序(因为您是这样打印的),最后我们将$project按您想要的实际形式进行排序。
对了,我们有你的结果。谢谢你问了个很酷的问题,让我们来看看双倍放松法的使用。

关于mongodb - Mongodb和聚合框架。对数组的元素求和以及文档的元素,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22018494/

10-11 00:30