这可能是一个远景,但是:
我想按日期之间的间隔对一组时间序列文档进行分组:按日期升序对文档进行排序,然后在当前文档与前一个文档之间的间隔超过某个阈值时进行分区。
当然,在获得文件后,我可以轻松地做到这一点;在此示例中,原始文档将获得一个新的分区号字段:
// assuming sorted docs
var partition = 0;
var partitioned = docs.map((e,i) => {
if(i > 0)
if(e.date - docs[i-1].date > minInterval) partition++;
return {
date: e.date,
partition: partition
}
});
但是我实际上并不需要文档本身,我只需要每个分区的起止日期和文档数量。尚不清楚我将如何执行分区功能。
使用汇总有可能吗?我看到possibly relevant Mondo ticket打开了,所以我猜没有。
答案 0 :(得分:1)
是的,有可能。要比较多个文档,您需要使用$group将它们放在一个数组中,并将null
传递为_id
。然后,要开始比较值,就需要像for循环一样的索引,以便可以使用$range运算符生成它。
要确定分区,您需要加倍$map。第一个将返回0
和1
值的数组,其中1
表示此日期开始新分区。
第二$map
将日期与分区索引合并。要获取分区索引,您可以$sum零和一的子数组($slice)。
例如:
db.col.save({ date: ISODate("2019-04-12T21:00:00.000Z") })
db.col.save({ date: ISODate("2019-04-12T21:15:00.000Z") })
db.col.save({ date: ISODate("2019-04-12T21:45:00.000Z") })
db.col.save({ date: ISODate("2019-04-12T23:00:00.000Z") })
db.col.save({ date: ISODate("2019-04-12T20:00:00.000Z") })
db.col.save({ date: ISODate("2019-04-12T18:30:00.000Z") })
db.col.save({ date: ISODate("2019-04-12T20:10:00.000Z") })
您可以在20
分钟的间隔内运行以下汇总:
db.col.aggregate([
{ $sort: { date: 1 } },
{ $group: { _id: null, dates: { $push: "$date" } } },
{
$addFields: {
partitions: {
$map: {
input: { $range: [ 0, { $size: "$dates" } ] },
as: "index",
in: {
$let: {
vars: {
current: { $arrayElemAt: [ "$dates", "$$index" ] },
prev: { $arrayElemAt: [ "$dates", { $add: [ "$$index", -1 ] } ] }
},
in: {
$cond: [
{ $or: [ { $eq: [ "$$index", 0 ] }, { $lt: [ { $subtract: [ "$$current", "$$prev" ] }, 1200000 ] } ] },
0,
1
]
}
}
}
}
}
}
},
{
$project: {
datesWithPartitions: {
$map: {
input: { $range: [ 0, { $size: "$dates" } ] },
as: "index",
in: {
date: { $arrayElemAt: [ "$dates", "$$index" ] },
partition: { $sum: { $slice: [ "$partitions", { $add: [ "$$index", 1 ] } ] } }
}
}
}
}
}
])
哪个将打印:
{
"_id" : null,
"datesWithPartitions" : [
{
"date" : ISODate("2019-04-12T18:30:00Z"),
"partition" : 0
},
{
"date" : ISODate("2019-04-12T20:00:00Z"),
"partition" : 1
},
{
"date" : ISODate("2019-04-12T20:10:00Z"),
"partition" : 1
},
{
"date" : ISODate("2019-04-12T21:00:00Z"),
"partition" : 2
},
{
"date" : ISODate("2019-04-12T21:15:00Z"),
"partition" : 2
},
{
"date" : ISODate("2019-04-12T21:45:00Z"),
"partition" : 3
},
{
"date" : ISODate("2019-04-12T23:00:00Z"),
"partition" : 4
}
]
}