MongoDB分组并计算不同文档的差值

6
在我的应用程序中,我有以下文档。
{
   "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,
}

我应如何返回按时间戳分组的 (进气-出气) 差值? 我正在尝试编写一个函数,使其返回以下结果:
{
   "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
},

我尝试使用聚合函数和$subtract操作符,阅读了其他SO问题,但它们似乎没有解决我的问题。 在其他问题中,他们似乎知道要从哪两个文档中进行减法计算,但在我的情况下,我不知道有多少个文档,并且$timestamp“列”是匹配两个文档的标识符。

有人能帮助我解决这个问题吗?谢谢!

1个回答

8
你首先需要的是在每个值的分组中基于条件$cond操作符进行条件$sum。然后你可以分别使用$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" ] }
    }}
])

这将给出以下结果:

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

替代方法就是将单个阶段的“gas-out”值设为负数:
db.gas.aggregate([
    { "$group": {
        "_id": "$timestamp",
        "gasdifference": { 
            "$sum": { 
                "$cond": [
                    { "$eq": [ "$sensor", "gas-in" ] },
                    "$value", 
                    { "$subtract": [ 0, "$value" ] }
                ]
            }
        }
    }}
])

这将更加高效。

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

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

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


嗨,Blakes Seven,感谢您的建议。我想我理解了“更有效的聚合”是什么,但我该如何将其整合到您的第一个建议中呢? - Jelmer Keij
@JelmerKeij 集成了。也许你的意思是说“sensor”中不仅仅只有“gas-in”和“gas-out”这两个可能的值。以下是一个示例,遵循三元条件逻辑。 - Blakes Seven
Blakes,非常感谢你的帮助。对于我来说,聚合仍然是一个棘手的主题。 - Jelmer Keij

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接