Агрегация MongoDB: получать образцы через определенные интервалы - PullRequest
0 голосов
/ 02 октября 2018

У меня есть коллекция MongoDB, содержащая документы с метками времени.Важной частью их формы является:

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

Они индексируются на дату.

Эти документы относятся и содержат данные из 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 запрос на отметку времени параллельно.Это также дает правильный результат и намного быстрее, но наличие нескольких тысяч временных отметок не является редкостью.Я не хочу делать тысячи запросов каждый раз, когда мне нужно это сделать.

...