MongoDb聚合具有多个分组的管道

时间:2016-10-31 12:52:05

标签: mongodb mongodb-query aggregation-framework

我正试图让我的脑袋围绕MongoDb中有多个群体的聚合管道。

我有以下数据:https://gist.github.com/bomortensen/36e6b3fbc987a096be36a66bbfe30d82

预期数据为:https://gist.github.com/bomortensen/7b220df1f1da83be838acfb2ed79a2ee(基于最高版本的总数量,每小时)

我需要编写一个执行以下操作的查询:

  1. 按字段MeterId对数据进行分组,以获取唯一的流量计组。
  2. 在每个组中,我需要按StartDate的年,月,日和小时进行分组,因为所有对象StartDate都存储为季度,但我需要将它们合并为整个小时。
    1. 最后,我只需Versions
    2. VersionNumber数组中获取最高版本
  3. 我尝试了以下查询,但必须承认我被卡住了:

    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 } }
    ]);
    

    有谁知道我应该怎么做? : - )

2 个答案:

答案 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)

这会给:

  • 1 $project:从日期开始$hour,每条记录创建一个maxVersion字段
  • 1 $unwind删除Versions数组
  • 1 $project添加一个keep字段,其中包含一个布尔值以检查是否应该保留记录
  • 1 $match仅匹配更高版本号,例如keep == true
  • 1 $group按ID /小时分组,并将数量相加
  • 1 $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之后,我添加了:

  • 1 $group推送以前在数组中过滤的版本
  • 1 $project $slice此数组仅采用第一个元素
  • 1 $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 }