MongoDB 按嵌套字段与组聚合并按另一个字段计数
MongoDB aggregate with group by nested field and count by another field
我有如下三个不同的文档
{
"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 中实现这一点?这可以使用 facet 完成吗?
如何聚合动态生成输出键?是否有任何可能的方法来使用单个 mongo 查询获取详细信息下的所有可用键?
按照以下步骤操作:
通过 $objectToArray 将 "detail" 对象转换为数组。现在,详细信息字段看起来像 "details: [{k: "city", v: "abc"}, {v: "dep", k: "dev"}]
$展开 "details" 数组字段。
$project 新标签 "label: $details.k_$details.v"
.
$按新标签和类别分组。
按类别$分组。
db.collections.aggregate([
{
$project: {
"category": 1,
"details": { $objectToArray: "details"}
}
},
{
$unwind: "details"
},
{
$project: {
"label": { $concat ["$details.k", '_', "$details.v"]}
}
},
{
$group: {
"_id": {
"label": "label",
"category": "category"
},
"count": {$sum: 1}
}
},
{
$group: {
"_id": "_id.label",
"summary": {
$push: {
"category": "$_id.category",
"count": "$count"
}
}
}
}
])
您需要运行以下聚合管道才能获得所需的结果:
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" }
} }
])
我有如下三个不同的文档
{
"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 中实现这一点?这可以使用 facet 完成吗? 如何聚合动态生成输出键?是否有任何可能的方法来使用单个 mongo 查询获取详细信息下的所有可用键?
按照以下步骤操作:
通过 $objectToArray 将 "detail" 对象转换为数组。现在,详细信息字段看起来像 "details: [{k: "city", v: "abc"}, {v: "dep", k: "dev"}]
$展开 "details" 数组字段。
$project 新标签 "label: $details.k_$details.v"
.
$按新标签和类别分组。
按类别$分组。
db.collections.aggregate([
{
$project: {
"category": 1,
"details": { $objectToArray: "details"}
}
},
{
$unwind: "details"
},
{
$project: {
"label": { $concat ["$details.k", '_', "$details.v"]}
}
},
{
$group: {
"_id": {
"label": "label",
"category": "category"
},
"count": {$sum: 1}
}
},
{
$group: {
"_id": "_id.label",
"summary": {
$push: {
"category": "$_id.category",
"count": "$count"
}
}
}
}
])
您需要运行以下聚合管道才能获得所需的结果:
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" }
} }
])