【发布时间】:2019-06-20 22:24:51
【问题描述】:
我正在尝试执行高级分析查询来驱动 Web 应用程序。我正在使用带有TimescaleDB 的 Hapi、Objection、Knex 和 Postgres。对于典型的关系查询,这一切都运行良好。但是,我无法弄清楚如何执行此聚合查询,该查询涉及与从 Postgres 的generate_series 生成的匿名表连接。我不得不求助于编写原始 SQL,而不是 Objection/Knex 查询生成器。我正在使用一些 Postgres 的内置函数,以及来自 Timescale 的 time_bucket。 time_bucket 本质上是根据参数中指定的间隔创建数据汇总。查看此链接以了解有关我尝试做什么的更多信息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 日更新
我得到它来执行带有异议的查询。但是,我得到一个空数组作为结果。与我在上面制作的原始 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();
附件是 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
【问题讨论】:
-
您的代码仍有几个地方可能存在 sql 注入漏洞。你能发现工作的原始查询和 knex 生成的查询不同的地方吗?这也会告诉你为什么查询没有返回预期的结果。
-
就错位而言 - 我认为我的主要问题是 SQL 查询使用左连接。我不能使用左连接,因为我的选择语句必须基于我的模型 (
my_errors_table),而不是基于generate_series函数。使用 knex,我在告诉它在第一个查询而不是连接上应用 where 子句时遇到问题。似乎 where 查询正在应用于联接,而不是实际查询。这有意义吗?知道如何解决吗? -
我知道我有可能进行 SQL 注入,因为我使用的是 JS 的字符串插值,而不是 knex 的查询生成器。我希望通过我的 ORM 来解决这个问题,因此 SQL 注入目前对我来说不是问题。
标签: postgresql knex.js sql-function objection.js timescaledb