我在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
关于如何实现这一目标的任何想法?
提前感谢!
答案 0 :(得分:1)
要从JSONB字段中搜索特定密钥,您可以使用?
,?|
和?&
运算符,但从问题我相信您实际上是在尝试查找某些密钥具有某些关键字的所有行值。
PostgreSQL协议不支持将类型作为绑定传递,因此您需要将其作为原始字符串传递,就像您在第二个示例中所做的那样。
然而,你仍然在做一些非常奇怪的事情:
tx.select('*').from('table')
.whereRaw('cast(data->>? as boolean) = ?', [key, JSON.parse(value)]));
data->>?
将您的json属性值作为字符串返回。然后你将它转换为boolean并将它与一些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/en/blog/objection-js-postgresql-power-json-queries/找到基于knex的ORM objection.js明确支持postgres jsonb查询。
答案 1 :(得分:0)
绑定的工作原理:
首先,您需要知道您使用的lib的绑定工作方式。
在您提供的调试日志中,它显示您将first()
值为字符串:
$acao = Acao::where('estado_id', '1')->first();
因此,第一个查询及其实际的SQL转换是:
imagem
这提供了明确的语法错误,在Postgres日志中也可以看到。
第二个查询(当您手动投射时)失败,因为您只使用了2个而保留了3个绑定参数,第二个参数是按数组顺序if (!is_null($acao)) {
而不是type
:
key: 'admin', value: 'true', type: 'boolean'
自然会失败。
在您面前时,有一些SQL提示:
Postgres为您提供了一些其他选项/样式,您可以执行查询,以下是其他一些示例(所有结果都相同):
// 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;
您喜欢哪种风格完全取决于您的偏好,我只是指出您还可以做到这一点:)
希望,帮助:)