我正试图让我的脑袋围绕MongoDb中有多个群体的聚合管道。
我有以下数据:https://gist.github.com/bomortensen/36e6b3fbc987a096be36a66bbfe30d82
预期数据为:https://gist.github.com/bomortensen/7b220df1f1da83be838acfb2ed79a2ee(基于最高版本的总数量,每小时)
我需要编写一个执行以下操作的查询:
MeterId
对数据进行分组,以获取唯一的流量计组。StartDate
的年,月,日和小时进行分组,因为所有对象StartDate
都存储为季度,但我需要将它们合并为整个小时。
Versions
VersionNumber
数组中获取最高版本
我尝试了以下查询,但必须承认我被卡住了:
mycollection.aggregate([
{ $group: {
_id : { ediel: "$_id.MeterId", start: "$_id.StartDate" },
versions: { $push: "$Versions" }
}
},
{ $unwind: { path: "$versions" } },
{ $group: {
_id: {
hour: { $hour: "$_id.start.DateTime" },
key: "$_id"
},
quantitySum: { $sum: "$Versions.Quantity" }
}
},
{ $sort: { "_id.hour": -1 } }
]);
有谁知道我应该怎么做? : - )
答案 0 :(得分:1)
对不起,我只是没有找到一个直接的方式来绕过小时。您可以尝试以下方法。您将展开版本,以便您可以应用分组来收集最大版本,推送下一步的版本,即投影以使用最大版本和最终项目过滤匹配的记录以汇总最大版本数量。现在开始dt是小组的最小值。只要你有一个小时的版本,你应该没事。
db.collection.aggregate([{
$unwind: {
path: "$Versions"
}
}, {
$group: {
_id: {
MeterId: "$_id.MeterId",
start: {
$hour: "$_id.StartDate"
}
},
startDate: {
$min: "$_id.StartDate"
},
maxVersion: {
$max: "$Versions.VersionNumber"
},
Versions: {
$push: "$Versions"
}
}
}, {
$sort: {
"_id.start": -1
}
}, {
$project: {
_id: {
MeterId: "$_id.MeterId",
StartDate: "$startDate"
},
hour: "$_id.start",
Versions: {
$filter: {
input: "$Versions",
as: "version",
cond: {
$eq: ["$maxVersion", "$$version.VersionNumber"]
}
}
}
}
}, {
$project: {
_id: 1,
hour: 1,
QuantitySum: {
$sum: "$Versions.Quantity"
}
}
}]);
示例输出
{
"_id": {
"MeterId": "1234",
"StartDate": ISODate("2016-09-20T02:00:00Z")
},
"QuantitySum": 15,
"hour": 2
}
答案 1 :(得分:1)
这会给:
$project
:从日期开始$hour
,每条记录创建一个maxVersion
字段$unwind
删除Versions
数组$project
添加一个keep
字段,其中包含一个布尔值以检查是否应该保留记录$match
仅匹配更高版本号,例如keep == true
$group
按ID /小时分组,并将数量相加$project
设置所需格式查询是:
db.mycollection.aggregate([{
$project: {
_id: 1,
Versions: 1,
hour: {
"$hour": "$_id.StartDate"
},
maxVersion: { $max: "$Versions.VersionNumber" }
}
}, {
$unwind: "$Versions"
}, {
$project: {
_id: 1,
Versions: 1,
hour: 1,
maxVersion: 1,
keep: { $eq: ["$Versions.VersionNumber", "$maxVersion"] }
}
}, {
$match: { "keep": true }
}, {
$group: {
_id: { _id: "$_id.MeterId", hour: "$hour" },
StartDate: { $first: "$_id.StartDate" },
QuantitySum: { $sum: "$Versions.Quantity" }
}
}, {
$project: {
_id: { _id: "$_id._id", StartDate: "$StartDate" },
hour: "$_id.hour",
QuantitySum: 1
}
}])
在您的示例输出中,您只考虑第一个较高版本号,{ "VersionNumber" : 2, "Quantity" : 7.5 }
和{ "VersionNumber" : 2, "Quantity" : 8.4 }
小时2
和ID 1234
,但您只需{ "VersionNumber" : 2, "Quantity" : 7.5 }
1}}
我不知道这是否有意,但在这种情况下,您只想获取第一个MaxVersion数字。在$match
之后,我添加了:
$group
推送以前在数组中过滤的版本$project
$slice
此数组仅采用第一个元素$unwind
删除此数组(仅包含一个元素)与您的输出匹配的查询是:
db.mycollection.aggregate([{
$project: {
_id: 1,
Versions: 1,
hour: {
"$hour": "$_id.StartDate"
},
maxVersion: { $max: "$Versions.VersionNumber" }
}
}, {
$unwind: "$Versions"
}, {
$project: {
_id: 1,
Versions: 1,
hour: 1,
maxVersion: 1,
keep: { $eq: ["$Versions.VersionNumber", "$maxVersion"] }
}
}, {
$match: { "keep": true }
}, {
$group: {
_id: { _id: "$_id.MeterId", StartDate: "$_id.StartDate" },
Versions: { $push: "$Versions" },
hour: { "$first": "$hour" }
}
}, {
$project: {
_id: 1,
hour: 1,
Versions: { $slice: ["$Versions", 1] }
}
}, {
$unwind: "$Versions"
}, {
$sort: {
_id: 1
}
}, {
$group: {
_id: { _id: "$_id._id", hour: "$hour" },
StartDate: { $first: "$_id.StartDate" },
QuantitySum: { $sum: "$Versions.Quantity" }
}
}, {
$project: {
_id: { _id: "$MeterId._id", StartDate: "$StartDate" },
Hour: "$_id.hour",
QuantitySum: 1
}
}])
输出是:
{ "_id" : { "MeterId" : "4567", "StartDate" : ISODate("2016-09-20T03:00:00Z") }, "QuantitySum" : 25.9, "Hour" : 3 }
{ "_id" : { "MeterId" : "4567", "StartDate" : ISODate("2016-09-20T02:00:00Z") }, "QuantitySum" : 25.9, "Hour" : 2 }
{ "_id" : { "MeterId" : "1234", "StartDate" : ISODate("2016-09-20T03:00:00Z") }, "QuantitySum" : 25.9, "Hour" : 3 }
{ "_id" : { "MeterId" : "1234", "StartDate" : ISODate("2016-09-20T02:00:00Z") }, "QuantitySum" : 25.9, "Hour" : 2 }