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