汇总非零值

时间:2018-11-23 20:48:33

标签: mongodb set

TL; DR

是否有mongo数组运算符可以检测数组是否包含至少一个大于前一个的条目?例如

 [1,1,1,2,2,2] -> true
 [1,1,1,0,0,0] -> false

我们正在使用mongo跟踪网络活动,其中相对字段packets是一段时间内活动的总和。最好通过示例来说明:

[0,0,0,0] -> no packets
[5,5,5,5] -> 5 packets continuous
[0,0,5,5] -> No packets and then a single event of 5
[0,0,5,10] -> two events, each increasing total packets by 5

我们的目标是识别有活动的记录(即,数据包数量发生变化)。首先,使用$addToSet运算符然后在count> 1处进行设置似乎很简单。EG:

[0,0,0,0] -> [0] -> false
[5,5,5,5] -> [5] -> false
[0,0,5,5] -> [0,5] -> true
[0,0,5,10] -> [0,5,10] -> true

但是,我们随后了解到一个附加约束。当活动变为0时,即被视为重置,因此不应计为活动,例如

[5,5,0,0] -> false (a reset event)
[0,0,5,5] -> true (a network event)
[5,0,5,0] -> true (a reset event followed be a network event followed by a reset - but because there was a network event this is true)

除了为零时,活动总是会增加(例如,[5,5,0,0]是可能的,但[5,5,4,4]则不是)。

因此,我们需要确定数据是否包含单个条目,其值大于前一个值。。是否有mongo运算符可以扫描数组并在任何元素大于其前一个元素的情况下返回true?

谢谢

2 个答案:

答案 0 :(得分:1)

您可以利用$reduce运算符来扫描数组,并保留先前的值以将其与当前值进行比较。

对于示例数据,例如:

db.col.aggregate([
    {
        $project: {
            result: {
                $reduce: {
                    input: "$data",
                    initialValue: {
                        previous: { $arrayElemAt: [ "$data", 0 ] },
                        decision: false
                    },
                    in: {
                        previous: "$$this",
                        decision: {
                            $or: [
                                "$$value.decision",
                                { $gt: [ "$$this", "$$value.previous" ] }
                            ]
                        }
                    }
                }
            }
        }
    },
    {
        $project: {
            _id: 0,
            result: "$result.decision"
        }
    }
])

您可以运行:

{ "result" : true }
{ "result" : false }

输出:

data.table

答案 1 :(得分:1)

基本上,您正在使用$reduce进行遍历,使用当前值和先前值并进行比较

db.collection.aggregate([
  { "$addFields": {
    "result": {
      "$reduce": {
        "input": {
          "$range": [ 1, { "$size": "$source_array" } ]
        },
        "initialValue": false,
        "in": {
          "$or": [
            "$$value",
            { "$gt": [
              { "$arrayElemAt": [ "$source_array", "$$this" ]},
              { "$arrayElemAt": [
                "$source_array",
                { "$subtract": [ "$$this", 1 ] }
              ]}
            ]}
          ]
        }
      }
    }
  }}
]);

给出如下数据:

{ "source_array" : [ 0, 0, 0, 0 ], "expect" : false }
{ "source_array" : [ 5, 5, 5, 5 ], "expect" : false }
{ "source_array" : [ 0, 0, 5, 5 ], "expect" : true }
{ "source_array" : [ 5, 5, 0, 0 ], "expect" : false }
{ "source_array" : [ 5, 0, 5, 0 ], "expect" : true }
{ "source_array" : [ 5, 0, 5, 5 ], "expect" : true }
{ "source_array" : [ 5, 5, 4, 4 ], "expect" : false }

返回:

[
  {
    "source_array": [
      0,
      0,
      0,
      0
    ],
    "expect": false,
    "result": false
  },
  {
    "source_array": [
      5,
      5,
      5,
      5
    ],
    "expect": false,
    "result": false
  },
  {
    "source_array": [
      0,
      0,
      5,
      5
    ],
    "expect": true,
    "result": true
  },
  {
    "source_array": [
      5,
      5,
      0,
      0
    ],
    "expect": false,
    "result": false
  },
  {
    "source_array": [
      5,
      0,
      5,
      0
    ],
    "expect": true,
    "result": true
  },
  {
    "source_array": [
      5,
      0,
      5,
      5
    ],
    "expect": true,
    "result": true
  },
  {
    "source_array": [
      5,
      5,
      4,
      4
    ],
    "expect": false,
    "result": false
  }
]

所有这些都是通过将$arrayElemAt与数组中的索引值一起使用来完成的。使用$range1..length生成索引,并将nn-1分别作为当前索引和先前索引。

逻辑表明,获得true结果时无需进一步比较。