MongoDB 分组并从不同文档中减去值

Jel*_*eij 5 mongodb mongodb-query aggregation-framework

在我的申请中,我有以下文件

{
   "timestamp": ISODate("2015-09-17T21:14:35.0Z"),
   "sensor": "gas-in",
   "value": 2.5,
},
{
   "timestamp": ISODate("2015-09-17T21:14:35.0Z"),
   "sensor": "gas-out",
   "value": 2.0,
},
{
   "timestamp": ISODate("2015-09-17T21:20:35.0Z"),
   "sensor": "gas-in",
   "value": 6.3,
},
{
   "timestamp": ISODate("2015-09-17T21:20:35.0Z"),
   "sensor": "gas-out",
   "value": 0.8,
}
Run Code Online (Sandbox Code Playgroud)

...等等...

如何返回按时间戳分组的差异 (gas-in) - (gas-out) ?我正在尝试编写一个像这样返回它的函数:

{
   "timestamp": ISODate("2015-09-17T21:14:35.0Z"),
   "sensor": "gas-difference",
   "value": 0.5, // is calculated by 2.5 - 2.0
},
{
   "timestamp": ISODate("2015-09-17T21:20:35.0Z"),
   "sensor": "gas-difference",
   "value": 5.5, // is calculated by 6.3 - 0.8
},
Run Code Online (Sandbox Code Playgroud)

...等等...

我玩过聚合函数和 $subtract,阅读其他 SO 问题,但他们似乎没有回答我的问题。在其他问题中,他们似乎知道要从彼此中减去哪个 2 个文档,但在我的情况下,我不知道文档的数量,并且 $timestamp “列”是两个文档的匹配标识符。

有人可以帮我解决这个问题吗?谢谢!

Bla*_*ven 7

您首先需要的是$sum基于$cond每个值分组中的运算符的条件。然后你可以分别$subtract

db.gas.aggregate([
    { "$group": {
        "_id": "$timestamp",
        "gas-in": { 
            "$sum": { 
                "$cond": [
                    { "$eq": [ "$sensor", "gas-in" ] },
                    "$value", 
                    0
                ]
            }
        },
        "gas-out": { 
            "$sum": { 
                "$cond": [
                    { "$eq": [ "$sensor", "gas-out"] },
                    "$value", 
                    0
                ]
            }
        },
    }},
    { "$project": {
        "gasdifference": { "$subtract": [ "$gas-in", "$gas-out" ] }
    }}
])
Run Code Online (Sandbox Code Playgroud)

这给出了结果:

{ "_id" : ISODate("2015-09-17T21:20:35Z"), "gasdifference" : 5.5 }
{ "_id" : ISODate("2015-09-17T21:14:35Z"), "gasdifference" : 0.5 }
Run Code Online (Sandbox Code Playgroud)

另一种方法是使单个阶段的“gas-out”值为负:

db.gas.aggregate([
    { "$group": {
        "_id": "$timestamp",
        "gasdifference": { 
            "$sum": { 
                "$cond": [
                    { "$eq": [ "$sensor", "gas-in" ] },
                    "$value", 
                    { "$subtract": [ 0, "$value" ] }
                ]
            }
        }
    }}
])
Run Code Online (Sandbox Code Playgroud)

这会更有效率。

如果您有两个以上可能的“传感器”值,那么您只需“嵌套”以下$cond语句:

db.gas.aggregate([
    { "$group": {
        "_id": "$timestamp",
        "gasdifference": { 
            "$sum": { 
                "$cond": [
                    { "$eq": [ "$sensor", "gas-in" ] },
                    "$value", 
                    { "$cond": [
                        { "$eq": [ "$sensor", "gas-out" ] },
                        { "$subtract": [ 0, "$value" ] },
                        0
                    ]}
                ]
            }
        }
    }}
])
Run Code Online (Sandbox Code Playgroud)

由于它们是“三元”运算符( if-then-else ),因此任何进一步的逻辑都属于“else”条件。