web-dev-qa-db-ja.com

複数の値に対するPostgreSql JSONB SELECT

いくつかのサンプルデータを入力した非常にシンプルなJSONテーブルがあります。

CREATE TABLE jsonthings(d JSONB NOT NULL);

INSERT INTO jsonthings VALUES ('{"name":"First","tags":["foo"]}');
INSERT INTO jsonthings VALUES ('{"name":"Second","tags":["foo","bar"]}');
INSERT INTO jsonthings VALUES ('{"name":"Third","tags":["bar","baz"]}');
INSERT INTO jsonthings VALUES ('{"name":"Fourth","tags":["baz"]}');

CREATE INDEX ON jsonthings USING GIN(d);

SELECTを実行するときにインデックスを使用しようとしています。値が単一のアイテムである行を取得する単純なSELECTは問題なく機能します。

SELECT d FROM jsonthings WHERE d @> '{"name":"First"}';

しかし、nameの複数の値に一致するクエリを実行しようとすると、インデックスの使用方法がわかりません。私はもう試した:

SELECT d FROM jsonthings WHERE d->>'name' = ANY(ARRAY['First', 'Second']);
SELECT d FROM jsonthings WHERE d->'name' ?| ARRAY['First', 'Second'];
SELECT d FROM jsonthings WHERE d#>'{name}' ?| ARRAY['First','Second'];

そして、それらすべてがテーブルの順次スキャンを示しています(私はenable_seqscan=falseは、可能であればインデックスの使用を強制します)。インデックスを使用するようにクエリを書き直す方法はありますか?私ができることを知っています:

SELECT * FROM jsonthings WHERE d @> '{"name":"First"}' OR d @> '{"name":"Second"}';

しかし、可変長のクエリがあり、JDBCを使用しているため、クエリがPreparedStatementであるという利点が失われます。

tagsキーのいくつかの項目のいずれかに対して同様のクエリを表示することにも興味があります。たとえば、次のようにします。

SELECT d FROM jsonthings WHERE d @> '{"tags":["foo"]}' OR d @> '{"tags":["bar"]}';

ただし、複数の条件ではなくARRAYを使用し、インデックスを使用します。

これはPostgreSql 9.4にあります。

7
jgm

ドキュメント( http://www.postgresql.org/docs/9.4/static/datatype-json.html )から、式のインデックスを使用してみます。

CREATE INDEX idx_jsonthings_names ON jsonthings USING gin ((d -> 'name'));
SELECT d FROM jsonthings WHERE d @> '{"name": ["First", "Second"]}';
3
Mladen Uzelac

これは、Mladenによって提供された回答に対する応答です。コメントを残す十分な評判はありませんが、クエリが正しくないようで、混乱し、将来的に他の人を混乱させる可能性があるため、返信を希望しました。

あなたは次を使用して言及します:

SELECT d FROM jsonthings WHERE d @> '{"name": ["First", "Second"]}';

ただし、名前としてFirstまたはSecondのいずれかを含むエントリを取得するには、PostgreSQL 9.4.4でこれが機能しないようです。

SELECT d FROM jsonthings WHERE d @> '{"name": ["First", "Second"]}';
 d
---
(0 rows)

上記のクエリは、name属性に配列["First", "Second"]が含まれているエントリを取得しようとしているようです。

そのようなエントリを作成した場合:

INSERT INTO jsonthings VALUES ('{"name":["First", "Second"],"tags":["baz"]}');

そして、もう一度クエリを実行すると、結果が返されます。

SELECT d FROM jsonthings WHERE d @> '{"name": ["First", "Second"]}';
d
------------------------------------------------
{"name": ["First", "Second"], "tags": ["baz"]}
(1 row)

ただし、これは、name属性がFirstまたはのいずれかであるエントリをクエリするときにインデックスを使用する方法であった、元の投稿者が尋ねた質問とは異なりますSecond

SELECT * FROM jsonthings WHERE d @> '{"name":"First"}' OR d @> '{"name":"Second"}';

JSONで[〜#〜] or [〜#〜]クエリを実行することが可能であると他の人が考えないように、ここにこれを提供したかった誤解を招く可能性があるため、"name": ["First", "Second"]を提供する。

1
adamc