Javascript Knexjs PgSQL json查询

Javascript Knexjs PgSQL json查询,javascript,json,node.js,postgresql,knex.js,Javascript,Json,Node.js,Postgresql,Knex.js,我在Postgres中有一列存储了一些JSON数据。JSON没有定义的模式,但应该可以搜索具有某个指定键的所有记录 我正在使用KnexJS构建查询,到目前为止,我提出了以下建议: tx.select('*').from('table') .whereRaw('cast(data->>? as ?) = ?', [key, type, JSON.parse(value)])); 但它不起作用,因为我认为不可能指定类型 尽管如此,当我尝试像这样手动指定它时: tx.select('*'

我在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
关于我如何做到这一点有什么想法吗


提前谢谢

绑定如何工作:

首先,您需要知道绑定在所使用的库中是如何工作的

从您提供的调试日志中,它显示您将值
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日志中看到

第二个查询(手动强制转换时)失败,因为您保留了3个绑定参数,而只使用了2个,第二个参数是按数组顺序
类型
而不是

// 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为您提供了一些其他选项/样式来执行查询,下面是一些其他示例(所有示例都给出了相同的结果):

你喜欢什么样的风格完全取决于你的喜好,我只是想指出你还能做什么:)


希望有帮助:)

要从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)]));
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 } } ]
无论如何,由于对“true”字符串进行了显式转换,您的第二个示例也应该有效。我添加了knex示例,说明您的案例应该有效:

tx.select('*').from('table')
  .whereRaw('data->>? = ?', [key, JSON.parse(value)]));
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查询的更多信息,请参见此处。基于knex的ORM Objective.js明确支持postgres jsonb查询。

对不起,我在问题中输入了一个类型。第二个示例并没有失败,因为我使用了三个绑定,实际上我只使用了我想要的两个绑定。您可以在日志
knex:bindings['admin',true]+0ms
中看到这一点。这纯粹是代码片段中的一个错误,我理解第一个示例的实际输出是什么,我想问的是,是否有某种方法可以绕过这一点,为什么在第二个示例中也失败了。您可以尝试我提供的一个SQL tips示例。同样在第二次(手动转换)中,您可以尝试转换
也可以转换为
…=?::布尔'。对于第一个部分,您可以尝试使用
?`binding代替布尔部分的??