2017-06-08 4 views
1

私は、いくつかのJSONデータを格納するPostgresにカラムを持っています。 JSONにはスキーマは定義されていませんが、指定されたキーを持つすべてのレコードを検索することは可能です。Knexjs PgSQL 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

は、バインディングが動作する方法:すべての

まず、あなたが使用してLIBでどのように結合作業を知っている必要があります。

したがって
key: 'admin', value: 'true', type: 'boolean' 

最初のクエリとその実際のSQLの翻訳は次のとおりです:デバッグから

は、それはあなたが文字列として typeを評価することを示しているあなたが提供するログ

// 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つの結合パラメータを維持し、2番目のパラメータは代わりにvalueの配列順序typeであるため、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はあなたのクエリを実行し、ここでいくつかの他の例(すべて同じ結果を与える)していることができますどのようにあなたにいくつかの他のオプション/スタイルを提供します:

あなたが好む何スタイル
// 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 

は完全にあなたの好み次第ですし、私はちょうどあなたがそれを行うことができますどのように他を指摘しています:)

うまくいけば、助け:)

+0

申し訳ありませんが、私は実際に私の質問でタイプを作った。私は3つのバインディングを使用するので、2番目の例は失敗しません。実際には2つだけ使用します。ログでは、 'knex:bindings ['admin'、true] + 0ms'を見ることができます。/ そして、最初の例の実際の出力が何であるかを理解しています。これを回避する方法があるのか​​どうか、そして2番目の例でも失敗するのはなぜかと尋ねています。 – tiansivive

+0

私が提供したSQLのヒント例の1つを試すことができます。また、2番目(手動キャスティング)では 'value = 'を' ... =?:: boolean'としてキャストしようとすることもできます。最初のものについては、 '?'の代わりに '?'バインドを試みるかもしれません。 –

1

JSONBフィールドから特定のキーを検索するには、??|および?&演算子を使用できますが、質問から特定のキーが特定の値を持つすべての行を実際に検索しようとしていると思います。

PostgreSQLプロトコルは、型をバインディングとして渡すことをサポートしていないため、2番目の例で行ったように、未処理の文字列として渡す必要があります。

しかし、あなたはまだ、本当に奇妙な何かをやっている:

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

文字列としてあなたのJSON属性値を返しますdata->>?。次に、それをブール値に変換し、それをJSON.parse(値)である値と比較します。エラー{ key: 'admin', value: 'true', type: 'boolean' }から

あなたの価値がすでに実際の文字列であるので、これは動作するはずと思われる:とにかく

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

、また、あなたが2番目の例では、原因あなたの「真」に行って、明示的なキャストに働いている必要があります文字列。私はあなたのケースで動作する必要があることを示すknex例を追加しました:postgresqlのでjsonbクエリを行う方法

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 } } ] 

詳しい情報はhttps://www.vincit.fi/en/blog/objection-js-postgresql-power-json-queries/もベースのORMをknex objection.jsのpostgres jsonbクエリを明示的にサポートしていますここで見つけることができます。