MongoDB通过嵌套字段进行分组并按另一个字段进行计数

时间:2018-08-10 13:03:21

标签: mongodb aggregation-framework facet

我有以下三个不同的文件

{
  "category" : "aaaaa",
  "summary" : {
    "details" : {
      "city" : "abc"
      "year_of_reg" : "2012",
      "dept" : "dev"
    }
  }
}

{
  "category" : "bbbb",
  "summary" : {
    "details" : {
      "city" : "abc",
      "year_of_reg" : "2016",
      "dept" : "dev"
    }
  }
}

{
  "category" : "aaaaa",
  "summary" : {
    "details" : {
      "dept" : "ui",
      "year_of_reg" : "2018"
    }
  }
}

我想根据摘要中详细信息中可用的键对结果进行分组,并根据类别进行计数。最终结果应如下图所示

{
  "dep_dev":[
      {
         "category":"aaaaa",
         "count":1.0
      },
      {
         "category":"bbbb",
         "count":1.0
      }
   ],
   "dep_ui":[
      {
         "category":"aaaaa",
         "count":1.0
      }
   ],
   "year_of_reg_2012":[
      {
         "category":"aaaaa",
         "count":1.0
      }
   ],
   "year_of_reg_2016":[
      {
         "category":"bbbb",
         "count":1.0
      }
   ],
   "year_of_reg_2018":[
      {
         "category":"aaaaa",
         "count":1.0
      }
   ],      
   "city_abc":[
      {
         "category":"aaaaa",
         "count":1.0
      },
      {
         "category":"bbbb",
         "count":1.0
      }
   ]
}

这如何在mongo汇总中实现?可以使用构面吗? 聚合如何动态生成输出密钥?是否有可能使用单个mongo查询来获取详细信息下的所有可用键?

2 个答案:

答案 0 :(得分:1)

您需要运行以下聚合管道才能获得所需的结果:

db.getCollection('test').aggregate([
    /*
    1. Create a field with an array of the summary details key concatenated with their 
       corresponding values. 
    */
    { "$addFields": { 
        "summary": {
            "$map": {
                "input": { "$objectToArray": "$summary.details" },
                "as": "el",
                "in": {
                    "$concat": ["$$el.k", "_", "$$el.v"]
                }
            }
        }
    } },

    /*
    2. Flatten the new array to produce a copy of each document per array entry. 
    */
    { "$unwind": "$summary" },

    /*
    3. Group the documents initially by the key and category. 
    */
    { "$group": {
        "_id": { 
            "key": "$summary",
            "category": "$category"
        },
        "count": { "$sum": 1 }
    } },

    /*
    4. Group the input documents from the previous pipeline by the key and aggregate the 
       category and corresponding counts  
    */
    {  "$group": {
        "_id": "$_id.key",
        "counts": {
            "$push": {
                "category": "$_id.category",
                "count": "$count"
            }
        }
    } },

    /*
    4. Calculate accumulated values for all the input documents as a whole.
    */
    {  "$group": {
        "_id": null,
        "counts": {
            "$push": {
                "k": "$_id",
                "v": "$counts"
            }
        }
    } },
    { "$replaceRoot": {
        "newRoot": { "$arrayToObject": "$counts" }
    } } 
])

答案 1 :(得分:0)

请遵循以下步骤: 通过$ objectToArray将“详细信息”对象转换为数组。现在,详细信息字段看起来像<EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="number" />

$ unwinding“ details”数组字段。

$ project新标签"details: [{k: "city", v: "abc"}, {v: "dep", k: "dev"}]

$ group按新标签和类别进行分组。

$按类别分组。

"label: $details.k_$details.v"