MongoDB聚合:以特定间隔获取样本

时间:2018-10-02 11:08:51

标签: mongodb mongodb-query aggregation-framework

我有一个包含时间戳的文档的MongoDB集合。它们形状的重要部分是:

{
  receivedOn: {
    date: ISODate("2018-10-01T07:50:06.836Z")
  }
}

它们在日期被编入索引。

这些文档与不断到达服务器的UDP有关并包含来自UDP的数据。 UDP的速率有所不同,但通常约为每秒20个

我正在尝试从此收藏中取样。我有一个时间戳列表,我想获取过去最接近这些时间戳的文档。

例如,如果我有以下文件

{_id: 1, "receivedOn.date": ISODate("2018-10-01T00:00:00.000Z")}
{_id: 2, "receivedOn.date": ISODate("2018-10-01T00:00:02.000Z")}
{_id: 3, "receivedOn.date": ISODate("2018-10-01T00:00:04.673Z")}
{_id: 4, "receivedOn.date": ISODate("2018-10-01T00:00:05.001Z")}
{_id: 5, "receivedOn.date": ISODate("2018-10-01T00:00:09.012Z")}
{_id: 6, "receivedOn.date": ISODate("2018-10-01T00:00:10.065Z")}

和时间戳

new Date("2018-10-01T00:00:05.000Z")
new Date("2018-10-01T00:00:10.000Z")

我希望结果是

[
    {_id: 3, "receivedOn.date": ISODate("2018-10-01T00:00:04.673Z")},
    {_id: 5, "receivedOn.date": ISODate("2018-10-01T00:00:09.012Z")}
]

我使用汇总来完成这项工作。以下代码给出了正确的结果,但是速度慢并且似乎具有复杂性O(n*m),其中n是匹配的文档数,而m是时间戳数

const timestamps = [
    new Date("2018-10-01T00:00:00.000Z")
    new Date("2018-10-01T00:00:05.000Z")
    new Date("2018-10-01T00:00:10.000Z")
];

collection.aggregate([
    {$match: {
        $and: [
            {"receivedOn.date": {$lte: new Date("2018-10-01T00:00:10.000Z")}},
            {"receivedOn.date": {$gte: new Date("2018-10-01T00:00:00.000Z")}}
    ]},
    {$project: ...},
    {$sort: {"receivedOn.date": -1}},
    {$bucket: {
        groupBy: "$receivedOn.date",
        boundaries: timestamps,
        output: {
            docs: {$push: "$$CURRENT"}
        }
    }},
    // The buckets contain sorted arrays. The first element is the newest
    {$project: {
        doc: {
            $arrayElemAt: ["$docs", 0]
        }
    }},
    // Lift the document out of its bucket wrapper
    {$replaceRoot: {newRoot: "$doc"}}
]);

有没有办法使它更快?就像以某种方式告诉$bucket数据已排序一样?我假设这里花费最多的时间是$bucket试图弄清楚将文档放入哪个存储区。或者还有另一种更好的方法可以做到这一点?

我还尝试了每个时间戳并行运行一个findOne查询。这样也可以给出正确的结果,并且速度更快,但是具有数千个时间戳的情况并不少见。我不想每次都需要执行数千个查询。

0 个答案:

没有答案