MongoDB使用聚合框架计算组后的差异

时间:2014-09-14 22:34:57

标签: mongodb mongodb-query aggregation-framework

我尝试使用MongoDB Aggregation来分析数据。目前我有以下代码:

db.events.aggregate(
    [
        {
            $match: {
                $or: [
                    {codename: "IGNITION_ON"},
                    {codename: "IGNITION_OFF"}
                ]
            }
        },
        {
            $project: {
                asset: 1,
                codename: 1,
                createdAt: 1,
                fuel: 1,
                odometer: 1
            }
        },
        {
            $group: {
                _id: {
                    asset: "$asset",
                    codename: "$codename",
                    day: { $dayOfYear: "$createdAt"}, 
                    year: { $year: "$createdAt" }
                },
                sumOdometer: {$sum: "$odometer"},
                sumFuel: {$sum: "$fuel"}
            }
        }
    ]
)

上述代码检索所有车辆的所有点火开关,并在一天内计算其里程表和燃油的总和。问题是我需要获得以下输出,即一天内每辆车的燃油和里程表(距离和消耗量)的差异。

[
    {
        "asset" : ObjectId("540e5d8e44616e1c8b260000"), 
        "day" : 213, 
        "year" : 2014 
        "diffOdometer" : "5",
        "diffFuel" : "10"
    },
    ...
]
你能帮帮我吗?感谢。

1 个答案:

答案 0 :(得分:2)

在这种情况下,您似乎需要$first$last运算符。这些通常在$sort之后有意义,除非您完全确定所有文档的日期顺序都在增加:

db.events.aggregate([
    { "$sort": { "createdAt": 1 } },
    { "$group": {
        "_id": {
            "asset": "$asset",
            "day": { "$dayOfYear": "$createdAt" },
            "year": { "$year": "$createdAt" }
        },
        "firstOdometer": { "$first": "$odometer" },
        "lastOdometer": { "$last": "$odometer" },
        "firstFuel": { "$first": "$fuel" },
        "lastFuel": { "$last": "$fuel" }
    }},
    { "$project": {
        "_id": 1,
        "diffOdometer": { "$subtract": [ "$lastOdometer", "$firstOdometer" ] },
        "diffFuel": { "$subtract": [ "$lastFuel", "$firstFuel" ] }
    }}
])

然后当然,在从分组中获得这些值之后,使用$subtract运算符计算出“第一”和“最后”读数的“差异”。

不确定“点火”开/关事件与您的数据样本有什么相关性,但在这种情况下,它似乎不是“完全”的逻辑点,但当然会添加任何相关的$match标准管道的第一阶段。同时注意到放置$project管道阶段没有特别的优势。在这种情况下,这可能不会“减少”管道中的字段。管道“优化器”将仅考虑$group中指定的字段对其进行排序。从上面开始,它会从一开始就这样做,因此在$ match之后,只有四个字段会出现在管道文档中。

当然,这并没有考虑到“重新加油”,只是假设你开始使用燃料并以燃料结束而消耗的是差异。考虑到这一点,你可能会有一个“重新加油”的事件类型,你可以从中获得总投入量。就像这样:

db.events.aggregate([
    { "$sort": { "createdAt": 1 } },
    { "$group": {
        "_id": {
            "asset": "$asset",
            "day": { "$dayOfYear": "$createdAt" },
            "year": { "$year": "$createdAt" }
        },
        "firstOdometer": { "$first": "$odometer" },
        "lastOdometer": { "$last": "$odometer" },
        "firstFuel": { "$first": "$fuel" },
        "lastFuel": { "$last": "$fuel" },
        "reFuelled": {
            "$sum": { "$cond": [ 
                { "$eq": [ "codename", "REFUEL" ] },
                "$filled",
                0
            ] }
        }
    }},
    { "$project": {
        "_id": 1,
        "diffOdometer": { "$subtract": [ "$lastOdometer", "$firstOdometer" ] },
        "diffFuel": { 
            "$subtract": [ 
                "$lastFuel", 
                { "$add": [ "$firstFuel", "$reFuelled" ] }
            ] 
        }
    }}
])

或者无论如何都是这样的。

简短案例是获取“开始”和“结束”数据,然后将数学应用于这些点。