将 Postgres 的 generate_series 函数与 ObjectionJS/KnexJS 一起使用
Using Postgres's generate_series Function with ObjectionJS/KnexJS
我正在尝试执行高级分析查询来驱动 Web 应用程序。我在 TimescaleDB. It all is working well for typical relational queries. However, I cannot figure out how to perform this aggregation query that involves joining with an anonymous table that is generated from Postgres's generate_series
. I have had to resort to writing the raw SQL, rather than the Objection/Knex query builder. I am using a few of Postgres's built in functions, along with time_bucket
from Timescale. time_bucket
essentially creates a roll up of the data based on the interval specified in the argument. Check this link out for more information about what I'm attempt to do Gap Filling.
中使用 Hapi、Objection、Knex 和 Postgres
这是查询,它使用对象模型上的原始方法工作。我相信像这样进行字符串插值会导致潜在的 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();
我已经用 Objection/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" = ?'
感谢任何帮助,因为我没有使用 Objection 来执行此操作,也找不到任何相关文档。
2018 年 11 月 15 日更新
我得到它来执行带有 Objection 的查询。但是,结果我得到一个空数组。与我在上面制作的原始 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
Timescale 发布了一项名为 Time Bucket Gapfill 的新功能。它使这变得容易得多,因为您不再需要使用 generate_series
进行左连接来填充间隙。
我已经包含了一个示例,说明如何使用名为 Errors
的 ObjectionJS 模型来实现它。 time_bucket_gapfill
函数的输入是桶大小、时间戳列名称、startTS 和 endTS。 bucket size 变量应该是一个字符串 ""
(不是单引号)对应于 bucket 大小(例如:"10 seconds"
, "30 minutes"
, "1 hour"
, "1 day"
). startTS
和 stopTS
应该是 ISO 日期字符串。第二个 select 语句需要 COALESCE
以便如果在桶中没有数据的情况下生成一个桶,它将输出 0。需要 group by
才能根据您在 select
语句中提供的聚合 SQL 函数正确汇总数据。
import { raw } from 'objection';
const errors = await Errors
.query()
.select(
raw("time_bucket_gapfill(?, timestamp, ?, ?) AS bucket", [bucketWidth, startTS, endTS]),
raw('COALESCE(count(timestamp), 0) AS count'),
).where('device_id', deviceId)
.andWhere('timestamp', '>=', startTS)
.andWhere('timestamp', '<=', endTS)
.groupBy('bucket')
.orderBy('bucket');
我正在尝试执行高级分析查询来驱动 Web 应用程序。我在 TimescaleDB. It all is working well for typical relational queries. However, I cannot figure out how to perform this aggregation query that involves joining with an anonymous table that is generated from Postgres's generate_series
. I have had to resort to writing the raw SQL, rather than the Objection/Knex query builder. I am using a few of Postgres's built in functions, along with time_bucket
from Timescale. time_bucket
essentially creates a roll up of the data based on the interval specified in the argument. Check this link out for more information about what I'm attempt to do Gap Filling.
这是查询,它使用对象模型上的原始方法工作。我相信像这样进行字符串插值会导致潜在的 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();
我已经用 Objection/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" = ?'
感谢任何帮助,因为我没有使用 Objection 来执行此操作,也找不到任何相关文档。
2018 年 11 月 15 日更新
我得到它来执行带有 Objection 的查询。但是,结果我得到一个空数组。与我在上面制作的原始 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
Timescale 发布了一项名为 Time Bucket Gapfill 的新功能。它使这变得容易得多,因为您不再需要使用 generate_series
进行左连接来填充间隙。
我已经包含了一个示例,说明如何使用名为 Errors
的 ObjectionJS 模型来实现它。 time_bucket_gapfill
函数的输入是桶大小、时间戳列名称、startTS 和 endTS。 bucket size 变量应该是一个字符串 ""
(不是单引号)对应于 bucket 大小(例如:"10 seconds"
, "30 minutes"
, "1 hour"
, "1 day"
). startTS
和 stopTS
应该是 ISO 日期字符串。第二个 select 语句需要 COALESCE
以便如果在桶中没有数据的情况下生成一个桶,它将输出 0。需要 group by
才能根据您在 select
语句中提供的聚合 SQL 函数正确汇总数据。
import { raw } from 'objection';
const errors = await Errors
.query()
.select(
raw("time_bucket_gapfill(?, timestamp, ?, ?) AS bucket", [bucketWidth, startTS, endTS]),
raw('COALESCE(count(timestamp), 0) AS count'),
).where('device_id', deviceId)
.andWhere('timestamp', '>=', startTS)
.andWhere('timestamp', '<=', endTS)
.groupBy('bucket')
.orderBy('bucket');