繁体   English   中英

Knexjs PgSQL JSON查询

[英]Knexjs PgSQL json query

我在Postgres中有一列存储一些JSON数据。 JSON没有定义的架构,但是应该可以搜索具有某些指定键的所有记录。

我正在使用KnexJS来构建查询,到目前为止,我想到了这个:

tx.select('*').from('table')
.whereRaw('cast(data->>? as ?) = ?', [key, type, JSON.parse(value)]));

但这是行不通的,因为我认为不可能指定类型。

不过,当我尝试像这样手动指定时:

tx.select('*').from('table')
.whereRaw('cast(data->>? as boolean) = ?', [key, JSON.parse(value)]));

它仍然不起作用! 这是使用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

关于如何实现此目标的任何想法?

提前致谢!

要从JSONB字段中搜索特定密钥,可以使用? ?| ?&运算符,但是从问题上来说,我相信您实际上是在寻找某些键具有特定值的所有行。

PostgreSQL协议不支持将传递类型作为绑定,因此您需要像在第二个示例中所做的那样将其作为原始字符串传递。

但是,您仍然在那做一些非常奇怪的事情:

tx.select('*').from('table')
  .whereRaw('cast(data->>? as boolean) = ?', [key, JSON.parse(value)]));

data->>? 返回您的json属性值作为字符串。 然后,将其转换为布尔值,并将其与JSON.parse(value)的某个值进行比较,这可能几乎是任何东西。

从错误{ key: 'admin', value: 'true', type: 'boolean' }看来,您的值实际上已经是一个字符串,因此应该可以使用:

tx.select('*').from('table')
  .whereRaw('data->>? = ?', [key, JSON.parse(value)]));

无论如何,由于对“ 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 } } ]

更多有关如何使用postgresql执行jsonb查询的信息,请参见https://www.vincit.fi/zh/blog/objection-js-postgresql-power-json-queries/以及基于knex的ORM objection.js对postgres jsonb查询。

绑定如何工作:

首先,您需要了解绑定在您使用的lib中如何工作。

您提供的调试日志显示您的值type为字符串:

key: 'admin', value: 'true', type: 'boolean'

因此,第一个查询及其实际的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;

这提供了清晰的语法错误,该错误在Postgres日志中也可见。

第二个查询(当您手动强制转换时)失败,因为您仅使用2个保留了3个绑定参数,而第二个参数是按数组顺序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'

这自然会失败。

当您使用它时,一些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

您更喜欢哪种风格完全取决于您的偏好,我只是指出您还可以怎么做:)

希望可以帮助:)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM