我在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,然后更改为9001
在2017-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},
#...
这是非常正确的,因为它返回时间/值的交叉乘积
答案 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 ] } ]