首页 文章

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

提问于
浏览
1

我试图在MongoDb中使用多个组来控制聚合管道 .

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

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

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

  • 按字段 MeterId 对数据进行分组以获取唯一的仪表组 .

  • 在每个组中,我需要按 StartDate 的年,月,日和小时进行分组,因为所有对象 StartDate 都存储为季度,但我需要将它们聚合为整个小时 .

  • 最后,我只需通过 VersionNumberVersions 数组中获取最高版本

我尝试了以下查询,但必须承认我被卡住了:

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 回答

  • 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 }

    我不知道这是否有意,但在这种情况下,您只想获取第一个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 }
    
  • 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
    }
    

相关问题