tia*_*ive 5 javascript postgresql json node.js knex.js
我在 Postgres 中有一个列存储一些 JSON 数据。JSON 没有定义模式,但应该可以搜索具有某些指定键的所有记录。
我正在使用 KnexJS 构建查询,到目前为止我想出了这个:
tx.select('*').from('table')
.whereRaw('cast(data->>? as ?) = ?', [key, type, JSON.parse(value)]));
Run Code Online (Sandbox Code Playgroud)
但它不起作用,因为我认为不可能指定类型。
不过,当我尝试像这样手动指定它时:
tx.select('*').from('table')
.whereRaw('cast(data->>? as boolean) = ?', [key, JSON.parse(value)]));
Run Code Online (Sandbox Code Playgroud)
还是不行啊!这是使用时控制台的日志DEBUG:knex:*
{ key: 'admin', value: 'true', type: 'boolean' }
knex:tx trx1: Starting top level transaction +0ms
knex:pool INFO pool postgresql:pg:client0 - dispense() clients=1 available=0 +2ms
knex:client acquired connection from pool: __knexUid2 +38ms
knex:query BEGIN; +2ms
knex:bindings undefined +1ms
knex:query select * from "contexts" where cast(data->>? as boolean) = ? +18ms
knex:bindings [ 'admin', true ] +0ms
knex:query COMMIT; +9ms
knex:bindings undefined +0ms
knex:tx trx1: releasing connection +6ms
knex:client releasing connection to pool: __knexUid2 +1ms
knex:pool INFO pool postgresql:pg:client0 - dispense() clients=0 available=1 +1ms
Run Code Online (Sandbox Code Playgroud)
关于如何实现这一目标有什么想法吗?
提前致谢!
要从 JSONB 字段搜索特定键,您可以使用?,?|和?&运算符,但从问题来看,我相信您实际上是在尝试查找某些键具有特定值的所有行。
PostgreSQL 协议不支持将类型作为绑定传递,因此您需要将其作为原始字符串传递,就像在第二个示例中所做的那样。
然而你仍然在那里做一些非常奇怪的事情:
tx.select('*').from('table')
.whereRaw('cast(data->>? as boolean) = ?', [key, JSON.parse(value)]));
Run Code Online (Sandbox Code Playgroud)
data->>?以字符串形式返回您的 json 属性值。然后将其转换为布尔值并将其与 JSON.parse(value) 的某个值进行比较,该值可能是任何值。
从错误{ key: 'admin', value: 'true', type: 'boolean' }看来,您的值实际上已经是一个字符串,所以这应该有效:
tx.select('*').from('table')
.whereRaw('data->>? = ?', [key, JSON.parse(value)]));
Run Code Online (Sandbox Code Playgroud)
无论如何,由于对“true”字符串进行了显式转换,您的第二个示例也应该有效。我添加了 knex 示例,表明您的案例应该有效:
await knex.schema.createTable('test2', t => {
t.increments('id');
t.jsonb('test');
});
await knex('test2').insert([
{ test: '{ "a": true, "b": false }' },
{ test: '{ "b": true, "a": false }' }
]);
await knex('test2').whereRaw('cast(test->>? as boolean) = ?', ['a', 'true']);
// outputs: [ anonymous { id: 1, test: { a: true, b: false } } ]
Run Code Online (Sandbox Code Playgroud)
更多如何使用 postgresql 进行 jsonb 查询的信息可以在这里找到https://www.vincit.fi/en/blog/objection-js-postgresql-power-json-queries/并且基于 knex 的 ORM objection.js 也明确支持postgres jsonb 查询。
小智 1
绑定如何工作:
首先,您需要知道绑定在您使用的库中如何工作。
从您提供的调试日志中,它显示您的值为type字符串:
key: 'admin', value: 'true', type: 'boolean'
Run Code Online (Sandbox Code Playgroud)
因此第一个查询及其实际的 SQL 翻译是:
// Your code:
tx.select('*').from('table')
.whereRaw('cast(data->>? as ?) = ?', [key, type, JSON.parse(value)]));
// Actual SQL:
SELECT * FROM "table" WHERE cast(data->>'admin' as 'boolean') = true;
Run Code Online (Sandbox Code Playgroud)
这提供了清晰的语法错误,该错误也可以在 Postgres 日志中看到。
第二个查询(当您手动转换时)失败,因为您保留了 3 个绑定参数,而仅使用 2 个参数,并且第二个参数是按数组顺序type而不是value:
// Your code:
tx.select('*').from('table')
.whereRaw('cast(data->>? as boolean) = ?', [key, JSON.parse(value)]));
// Actual SQL:
SELECT * FROM "table" WHERE cast(data->>'admin' as boolean) = 'undefined'
Run Code Online (Sandbox Code Playgroud)
这自然会失败。
当您使用它时,一些 SQL 提示:
Postgres 为您提供了一些其他选项/样式来执行查询,这里有一些其他示例(都给出相同的结果):
// Casting with `=` s
SELECT * FROM table WHERE (data ->> 'admin')::boolean = TRUE // finds all `true` values
SELECT * FROM table WHERE NOT ( (data ->> 'admin')::boolean = FALSE ) // finds all 'false' values
// Since every condition in WHERE ends up boolean you can avoid
// using `=` comparsion and shorten the code
SELECT * FROM table WHERE (data ->> 'admin')::boolean // finds all `true` values
SELECT * FROM table WHERE NOT ( (data ->> 'admin')::boolean ) // finds all 'false' values
// When using JSONB data type you can use `->` operator instead
SELECT * FROM table WHERE data -> 'admin' = 'true' // finds all `true` values
SELECT * FROM table WHERE NOT ( data -> 'admin' = 'false' ) // finds all 'false' values
Run Code Online (Sandbox Code Playgroud)
您喜欢什么风格完全取决于您的喜好,我只是指出您还可以如何做到这一点:)
希望有帮助:)
| 归档时间: |
|
| 查看次数: |
22442 次 |
| 最近记录: |