Mongo 3.2在特定时间查询时间序列值

时间:2017-03-15 18:11:48

标签: mongodb mongodb-query time-series

我在Mongo中存储了一些时间序列数据,每个帐户都有一个文档,如下所示:

{
    "account_number": 123,
    "times": [
         datetime(2017, 1, 2, 12, 34, 56),
         datetime(2017, 3, 4, 17, 18, 19),
         datetime(2017, 3, 11, 0, 1, 11),
    ]
    "values": [
         1,
        10,
       9001,
    ]
}

因此,要清楚上述代理帐户123的值为2017-01-02 12:34:56的值为1,直到2017-03-04 17:18:19上的值更改为10,然后更改为90012017-03-11, 00:01:11

帐户数量众多,每个帐户的数据都不同(可能在不同的时间,价值变化可能比其他帐户更多或更少)。

我想在给定时间查询每个用户的值,例如" 2017-01-30 02:03:04每个用户的价值是多少?如果上述帐户返回1,则会在给定时间之前将其设置为1,并且在给定时间之后才会更改。

看起来$zip会很有用,但这只适用于Mongo 3.4和我使用3.2并且没有计划很快升级。

编辑:

我可以使用以下方式获得一小部分:

> db.account_data.aggregate([{$unwind: '$times'}, {$unwind: '$values'}])

返回类似的内容:

{"account_number": 123, "times": datetime(2017, 1, 2, 12, 34, 56), "values": 1},
{"account_number": 123, "times": datetime(2017, 1, 2, 12, 34, 56), "values": 10},
#...

这是非常正确的,因为它返回时间/值的交叉乘积

2 个答案:

答案 0 :(得分:0)

不确定如何对MongoDb 3.2执行相同操作,但是从3.4您可以执行以下查询:

db.test.aggregate([
{
    $project:
      {
        index: { $indexOfArray: [ "$times", "2017,3,11,0,1,11" ] },
        values: true
      }
},
{
  $project: {
    resultValue: { $arrayElemAt: [ "$values", "$index" ] }
  }
}])

答案 1 :(得分:0)

仅使用3.2功能即可实现。我使用Mingo库进行了测试

var mingo = require('mingo')

var data = [{
    "account_number": 123,
    "times": [
        new Date("2017-01-02T12:34:56"),
        new Date("2017-03-04T17:18:19"),
        new Date("2017-03-11T00:01:11")
    ],
    "values": [1, 10, 9001]
}]

var maxDate = new Date("2017-01-30T02:03:04")

// 1. filter dates down to those less or equal to the maxDate
// 2. take the size of the filtered date array
// 3. subtract 1 from the size to get the index of the corresponding value
// 4. lookup the value by index in the "values" array into new "valueAtDate" field
// 5. project the extra fields
var result = mingo.aggregate(data, [{
    $project: {
        valueAtDate: {
            $arrayElemAt: [
                "$values",
                { $subtract: [ { $size: { $filter: { input: "$times", as: "time", cond: { $lte: [ "$$time", maxDate ] }} } }, 1 ] }
            ]
        },
        values: 1,
        times: 1
    }
}])

console.log(result)

// Outputs
[ { valueAtDate: 1,
    values: [ 1, 10, 9001 ],
    times:
    [ 2017-01-02T12:34:56.000Z,
    2017-03-04T17:18:19.000Z,
    2017-03-11T00:01:11.000Z ] } ]