【发布时间】:2018-04-19 13:50:28
【问题描述】:
刚开始使用聚合或 map/reduce。我想要所有文档中名为“标签”的数组字段中的项目数。我正在使用猫鼬。谢谢!
例子:
文档 1
tags: ['A', 'B', 'C', 'D']
文档 2
tags: ['A', 'B']
文档 3
tags: ['D']
结果:{A: 2, B: 2, C: 1, D: 2}
还想要数组项的总数,以便我可以计算百分比(例如,A = 2/7)
【问题讨论】:
刚开始使用聚合或 map/reduce。我想要所有文档中名为“标签”的数组字段中的项目数。我正在使用猫鼬。谢谢!
例子:
文档 1
tags: ['A', 'B', 'C', 'D']
文档 2
tags: ['A', 'B']
文档 3
tags: ['D']
结果:{A: 2, B: 2, C: 1, D: 2}
还想要数组项的总数,以便我可以计算百分比(例如,A = 2/7)
【问题讨论】:
尽我所能,您可以这样做:
db.getCollection('tags').aggregate([
{ "$unwind": "$tags" },
{ "$group": {
"_id": "$tags",
"count": { "$sum": 1 }
}},
{ "$sort": { "_id": 1 } },
{ "$group": {
"_id": null,
"tags": { "$push": { "k": "$_id", "v": "$count" } }
}},
{ "$replaceRoot": {
"newRoot": {
"$mergeObjects": [
{ "$arrayToObject": "$tags" },
{ "total": { "$sum": "$tags.v" } }
]
}
}}
])
如果您没有 MongoDB 3.6 功能,您可以像这样简单地转换输出:
db.getCollection('tags').aggregate([
{ "$unwind": "$tags" },
{ "$group": {
"_id": "$tags",
"count": { "$sum": 1 }
}},
{ "$sort": { "_id": 1 } },
{ "$group": {
"_id": null,
"tags": { "$push": { "k": "$_id", "v": "$count" } }
}}
]).map( d =>
Object.assign(
d.tags.reduce((acc,curr) => Object.assign(acc, { [curr.k]: curr.v }), {}),
{ total: d.tags.reduce((acc,curr) => acc + curr.v, 0) }
)
)
无论哪种方式都会产生:
{
"A" : 2.0,
"B" : 2.0,
"C" : 1.0,
"D" : 2.0,
"total" : 7.0
}
如果您想要其中的“百分比”,您可以对输出进行后期处理,因为所有数字都已经存在,或者只是更改处理。
对于 MongoDB 3.6
db.getCollection('tags').aggregate([
{ "$unwind": "$tags" },
{ "$group": {
"_id": "$tags",
"count": { "$sum": 1 }
}},
{ "$sort": { "_id": 1 } },
{ "$group": {
"_id": null,
"tags": { "$push": { "k": "$_id", "v": "$count" } } ,
"total": { "$sum": "$count" }
}},
{ "$replaceRoot": {
"newRoot": {
"$mergeObjects": [
{ "$arrayToObject": {
"$map": {
"input": "$tags",
"in": {
"k": "$$this.k",
"v": {
"count": "$$this.v",
"perc": { "$multiply": [{ "$divide": [ "$$this.v", "$total" ] }, 100 ] }
}
}
}
}},
{ "total": "$total" }
]
}
}}
])
或更低版本,仍在处理输出:
db.getCollection('tags').aggregate([
{ "$unwind": "$tags" },
{ "$group": {
"_id": "$tags",
"count": { "$sum": 1 }
}},
{ "$sort": { "_id": 1 } },
{ "$group": {
"_id": null,
"tags": { "$push": { "k": "$_id", "v": "$count" } },
"total": { "$sum": "$count" }
}}
]).map( d =>
Object.assign(
d.tags.reduce((acc,curr) =>
Object.assign(acc, { [curr.k]: { count: curr.v, perc: curr.v / d.total * 100 } }),
{}
),
{ total: d.total }
)
)
输出包括每个分组键上的两个键:
{
"A" : {
"count" : 2.0,
"perc" : 28.5714285714286
},
"B" : {
"count" : 2.0,
"perc" : 28.5714285714286
},
"C" : {
"count" : 1.0,
"perc" : 14.2857142857143
},
"D" : {
"count" : 2.0,
"perc" : 28.5714285714286
},
"total" : 7.0
}
请注意,MongoDB shell 对现代 JavaScript 功能有些限制。在现代 JavaScript 环境中,例如最近发布的 Nodejs,您可以缩短转换时间:
result.map(({ _id, tags, ...d }) =>
({
..tags.reduce((acc,curr) =>
({ ...acc, [curr.k]: { count: curr.v, perc: curr.v / d.total * 100 }),
{}
),
...d
})
)
【讨论】: