我在MongoDB上遇到聚合查询问题。
我有一个以下结构的文件:
FileReference
我想要计算与arr_vs项目相关的每个值。
预期产出:
[{
"_id": ObjectId("19a5070b808028108101"),
"arr_vs": [
{
"arr_id": "one",
"val": 5
},
{
"arr_id": "two",
"val": 5
}]
},
{
"_id": ObjectId("19a5070b80802810810"),
"arr_vs": [
{
"arr_id": "one",
"val": 5
},
{
"arr_id": "two",
"val": 2
},{
"arr_id": "three",
"val": 1
}]
}]
任何帮助将不胜感激。
答案 0 :(得分:0)
输出到命名键绝不是一些人似乎认为它的奇妙之处。实际上,我通常希望使用返回的结果,因此一个" list / array"更有意义。
这基本上是每个新人基本上被告知放弃他们的"命名键"概念,并意识到他们正在使用数据库和命名键的固有问题。这也是为什么收藏本质上是"列表"同样。
所以你最好习惯这个概念:
db.collection.aggregate([
{ "$unwind": "$arr_vs" },
{ "$group": {
"_id": { "id": "$arr_vs.arr_id", "val": "$arr_vs.val" },
"total_count": { "$sum": 1 }
}},
{ "$group": {
"_id": "$_id.id",
"v": {
"$push": {
"val": "$_id.val",
"total_count": "$total_count"
}
}
}}
])
这基本上会给你:
/* 1 */
{
"_id" : "two",
"v" : [
{
"val" : 2.0,
"total_count" : 1.0
},
{
"val" : 5.0,
"total_count" : 1.0
}
]
}
/* 2 */
{
"_id" : "one",
"v" : [
{
"val" : 5.0,
"total_count" : 2.0
}
]
}
/* 3 */
{
"_id" : "three",
"v" : [
{
"val" : 1.0,
"total_count" : 1.0
}
]
}
聚合数据是一种可迭代且易于使用的形式。
如果您打算使用输出格式并至少拥有MongoDB 3.4.4版本,则可以通过压缩文档并使用$arrayToObject
来进一步实现:
db.collection.aggregate([
{ "$unwind": "$arr_vs" },
{ "$group": {
"_id": { "id": "$arr_vs.arr_id", "val": "$arr_vs.val" },
"total_count": { "$sum": 1 }
}},
{ "$group": {
"_id": "$_id.id",
"v": {
"$push": {
"val": "$_id.val",
"total_count": "$total_count"
}
}
}},
{ "$group": {
"_id": null,
"arr_vs": {
"$push": {
"k": "$_id",
"v": "$v"
}
}
}},
{ "$project": {
"_id": 0,
"arr_vs": { "$arrayToObject": "$arr_vs" }
}}
])
或者甚至只是应用最终的"重塑"客户端,如果你的MongoDB版本不支持new运算符:
db.collection.aggregate([
{ "$unwind": "$arr_vs" },
{ "$group": {
"_id": { "id": "$arr_vs.arr_id", "val": "$arr_vs.val" },
"total_count": { "$sum": 1 }
}},
{ "$group": {
"_id": "$_id.id",
"v": {
"$push": {
"val": "$_id.val",
"total_count": "$total_count"
}
}
}},
{ "$group": {
"_id": null,
"arr_vs": {
"$push": {
"k": "$_id",
"v": "$v"
}
}
}},
/*
{ "$project": {
"_id": 0,
"arr_vs": { "$arrayToObject": "$arr_vs" }
}}
*/
]).map( d => ({
"arr_vs": d.arr_vs.reduce((acc,curr) =>
Object.assign(acc,({ [curr.k]: curr.v })),{})
}))
两者产生相同的输出:
{
"arr_vs" : {
"two" : [
{
"val" : 2.0,
"total_count" : 1.0
},
{
"val" : 5.0,
"total_count" : 1.0
}
],
"one" : [
{
"val" : 5.0,
"total_count" : 2.0
}
],
"three" : [
{
"val" : 1.0,
"total_count" : 1.0
}
]
}
}