Я пытаюсь выполнять расширенные аналитические запросы для управления веб-приложением.Я использую Hapi, Objection, Knex и Postgres с TimescaleDB .Все это хорошо работает для типичных реляционных запросов.Однако я не могу понять, как выполнить этот запрос агрегации, который включает соединение с анонимной таблицей, сгенерированной из Postgres generate_series
.Мне пришлось прибегнуть к написанию необработанного SQL, а не к построителю запросов Objection / Knex.Я использую несколько встроенных функций Postgres, а также time_bucket
из Timescale.time_bucket
по существу создает свертку данных на основе интервала, указанного в аргументе.Проверьте эту ссылку для получения дополнительной информации о том, что я пытаюсь сделать Заполнение пробела .
Вот запрос, который работает с использованием необработанного метода в модели возражений.Я полагаю, что выполнение такой интерполяции строк приведет к потенциальной инъекции SQL.Однако я надеялся преобразовать это в методы построителя запросов, которые использует Objection / Knex, так что это больше JavaScript, чем SQL, что решило бы проблему внедрения SQL.
let errorHistorgram = await Errors
.raw(`SELECT period AS daily, coalesce(count,0) AS count
FROM generate_series(date '${startTS}', date '${today}', interval '1d') AS period
LEFT JOIN (
SELECT time_bucket('1d',timestamp)::date AS date, count(timestamp)
FROM my_error_table
WHERE severity = 'HIGH'
AND timestamp >= '${startTS}' AND timestamp < '${today}'
AND device_id = ${deviceId}
GROUP BY date
) t ON t.date = period;`)
.debug();
Я сделал несколько попытокна это с возражением / Knex.Это была моя самая успешная попытка создать этот запрос.Однако я считаю, что предложение where находится не в правильном месте.
let errorHistorgram = await Errors
.query()
.select(raw(`time_bucket('1 day', timestamp) AS daily, count(timestamp)`))
.where('device_id', deviceId)
.andWhere('timestamp', '>', startTS)
.andWhere('severity', 'HIGH')
.leftJoin(`generate_series(date ${startTS}, date ${today}, interval 1d) AS series`, 'series.date', 'my_error_table.timestamp')
.debug();
С помощью .debug()
я могу увидеть вывод запроса, который опубликован ниже.
select time_bucket('1 day', timestamp) AS daily, count(timestamp)
from my_error_table
left join "generate_series(date 2018-11-08T15:35:33"."050Z, date 2018-11-15T15:35:33"."133Z, interval 1d)" as "series"
on "series"."date" = my_error_table."timestamp"
where "device_id" = ? and "timestamp" > ? and "severity" = ?'
Любая помощь приветствуется, поскольку я не использовал для этого возражения и не могу найти какую-либо документацию по ней.
ОБНОВЛЕНИЕ 11/15/2018
Я получил еевыполнить запрос с возражением.Тем не менее, я получаю пустой массив в результате.В отличие от необработанного SQL-запроса, который я создал выше (который дает ожидаемые результаты), я просто получаю пустой массив в качестве вывода для построителя запросов.Любая идея относительно того, что я делаю неправильно.Я попытался перевернуть соединение на правильное, но безуспешно.
let errorHistorgram = await Errors
.query()
.select(raw(`time_bucket('1 day', timestamp) AS daily, count(timestamp)`))
.where('device_id', deviceId)
.andWhere('timestamp', '>', startTS)
.andWhere('severity', 'HIGH')
.groupBy('timestamp')
.rightJoin(raw(`generate_series(date '${startTS}', date '${today}', interval '1d') AS series`), 'series.date', 'my_error_table.timestamp')
.debug();
Прилагается вывод SQL отладки.
select time_bucket('1 day', timestamp) AS daily, count(timestamp)
from my_errors_table
right join generate_series(date '2018-11-08', date '2018-11-15', interval '1d') AS series
on series = my_errors_table.timestamp
where device_id = ? and timestamp > ? and severity = ?
group by timestamp