我有一个类似以下的数据集
[{id:1,month:1,count:1},{id:1,month:2,count:2},{id:1,month:3,count:3}......,
{id:2,month:1,count:1},{id:2,month:2,count:2},{id:2,month:3,count:3}.......,
........
........
{id:19,month:1,count:1},{id:19,month:2,count:2},{id:19,month:3,count:3}.......,]
,表格如下所示。
|id|month|count|
|1 | 1 | 1 |
.............
.........
|19| 12 | 4 |
还有另一个id作为divisonId,它如下所示映射到上面的id
{1:[1,2,4,5],2:[3,6,8,9],3:[7,10,....19]}
,映射表如下所示。
|divisionId| id|
| 1 | 1 |
| 1 | 2 |
| 1 | 4 |
| 1 | 5 |
| 2 | 3 |
| 2 | 6 |
......
......
所以现在我需要汇总数据并求和并根据divisonIds重新分组。
所以最终返回的数据应该看起来像下面的
[{divsionId:1,month:1,count:19},{divisionId:1,month:2,count:53},{divisionId:1,month:3,count:66}......,
{divisionId:2,month:1,count:21},{divisionId:2,month:2,count:82},{divisionId:2,month:3,count:63}.......,
{divisionId:3,month:1,count:1},{divisionId:3,month:2,count:2},{divisionId:3,month:3,count:3}.......,]
表格应该像
| divisionId| month | count |
| 1 | 1 | 200 |
| 1 | 2 | 400 |
| 1 | 3 | 300 |
.....
.....
| 3 | 11 | 500 |
| 3 | 12 | 600 |
因此,基本上,它只是将ID映射到divisionId,并汇总这些ID的各个月份,然后汇总一个新的集合以返回数据。 由于将来可能会将ID分配给不同的dividId,或者不允许仅使用聚合方法,因此我不允许将dividId放在原始表中。
当前,我可以使用的一种方法是使用Javascript根据映射分别获取ID的数据,然后进行计算并将其推入mongos以便将其存储为新集合,因此当UI查询数据时将来,它将仅读取查询,从而节省了昂贵的计算。但是如果我仅通过使用一些高级mongodb语法就能解决此问题,那就太好了。如果您有一些技巧可以使用,请告诉我。谢谢。
答案 0 :(得分:0)
请尝试:
db.divisionIdCollName.aggregate([{
$lookup:
{
from: "idCollectionName",
let: { ids: "$id" },
pipeline: [
{
$match:
{
$expr:
{ $in: ["$id", "$$ids"] }
}
}
],
as: "data"
}
}, { $unwind: { path: "$data", preserveNullAndEmptyArrays: true } },
{ $group: { _id: { divisionId: '$divisionId', month: '$data.month' }, month: { $first: '$data.month' }, count: { $sum: '$data.count' } } },
{$addFields : {divisionId : '$_id.divisionId'}}, {$project : {_id:0}}
])
结果: Mongo playground
您可以在那儿测试结果-感到聚合正在返回正确的结果后,尝试添加$merge阶段以将结果写入另一个集合,您可以使用$out代替$merge
,但是我们使用$merge
的原因是,如果给定名称与数据库$out
中的任何集合名称匹配,则每次查询运行时它将用聚合结果替换整个集合,这将是破坏性的,如果该查询必须更新集合中的现有记录,这就是我们使用$merge
的原因,请在使用前先阅读这两条记录,因此在$project
之后的最后一个阶段添加以下阶段。
注意::$merge
中的v 4.2
是$out
> = v 2.6
中的新内容。如果您要进行$merge
,因为您要指定两个字段on: [ "divisionId", "month" ]
-那么应该在集合divisionIdCollNameNew
上创建一个唯一的复合索引-因此,我们需要手动创建集合并创建唯一索引,然后执行查询。
创建收藏夹和索引:
db.createCollection("divisionIdCollNameNew")
db.divisionIdCollNameNew.createIndex ( { divisionId: 1, month: 1 }, { unique: true } )
最终阶段:
{ $merge : { into: { coll: "divisionIdCollNameNew" }, on: [ "divisionId", "month" ], whenNotMatched: "insert" } }
答案 1 :(得分:0)
集合months
具有以下结构:{id:1,month:1,count:1}
集合divisions
具有以下结构:{1:[1,2,4,5],2:[3,6,8,9],3:[7,10,19]}
您可以执行以下查询:
db.divisons.aggregate([
{
$addFields: {
data: {
$filter: {
input: {
$objectToArray: "$$ROOT"
},
cond: {
$isArray: "$$this.v"
}
}
}
}
},
{
$unwind: "$data"
},
{
$lookup: {
from: "months",
let: {
ids: "$data.v"
},
pipeline: [
{
$match: {
$expr: {
$in: [
"$id",
"$$ids"
]
}
}
}
],
as: "months"
}
},
{
$unwind: "$months"
},
{
$group: {
_id: {
divisionId: "$data.k",
month: "$months.month"
},
count: {
$sum: "$months.count"
}
}
},
{
$project: {
_id: 0,
divisionId: "$_id.divisionId",
month: "$_id.month",
count: "$count"
}
},
{
$sort: {
divisionId: 1,
month: 1
}
}
])
您的divisions
集合尚未规范化key:value
对,因此我们的第一步是使用1:[...], 2:[...]
运算符将[{k:"1", v:[...]}, {k:2, v:[...]}]
对转换为$objectToArray
对。
然后,我们将上一步中的数组$unwind
展平,并将uncorrelated sub-queries的$lookup
应用于months
集合。
最后一步,我们用$group
divisionId + month
乘以count
的值。
为了将结果存储在另一个集合中,您需要使用$out or $merge运算符。