web-dev-qa-db-ja.com

Postgres JSON配列内のクエリ

json列に格納されている配列内の要素を検索するにはどうすればよいですか? (更新:jsonb列の9.4更新された回答も参照してください。)

このようなJSONドキュメントがある場合、jsonという名前のblob列に格納されます。

{"name": "Wolf",
 "ids": [185603363281305602,185603363289694211]}

私ができることは次のようなものです:

SELECT * from "mytable" WHERE 185603363289694211 = ANY("blob"->'ids');

一致するすべての行を取り出します。ただし、"blob"->'ids'はPostgres配列ではなくJSON値を返すため、これは機能しません。

可能であれば、個々のIDにインデックスを作成することもできます。

19
Joe Shaw

以下の元の回答はPostgres 9.3にのみ適用されます。 Postgres 9.4の回答については、以下の更新を参照してください。

これは Erwinの参照された回答 に基づいて構築されていますが、この質問にはもう少し明確です。

この場合のIDはbigintsなので、JSON配列をPostgres bigint配列に変換するヘルパー関数を作成します。

CREATE OR REPLACE FUNCTION json_array_bigint(_j json)
  RETURNS bigint[] AS
$$
SELECT array_agg(elem::text::bigint)
FROM json_array_elements(_j) AS elem
$$
  LANGUAGE sql IMMUTABLE;

代わりに、ここでtext配列を簡単に(そしておそらく再利用可能に)返すことができます。 bigintでのインデックス作成はtextよりもはるかに高速だと思いますが、それを裏付ける証拠をオンラインで見つけるのは困難です。

インデックスを作成する場合:

CREATE INDEX "myindex" ON "mytable" 
  USING GIN (json_array_bigint("blob"->'ids'));

クエリの場合、これは機能し、インデックスを使用します。

SELECT * FROM "mytable" 
  WHERE '{185603363289694211}' <@ json_array_bigint("blob"->'ids');

これを行うとクエリにも機能しますが、インデックスは使用しません。

SELECT * FROM "mytable" 
  WHERE 185603363289694211 = ANY(json_array_bigint("blob"->'ids'));

9.4のアップデート

Postgres 9.4はjsonbタイプを導入しました。 これは良いSO jsonbについての回答であり、jsonを超えて使用する必要がある場合 。要するに、 JSONをクエリする場合は、jsonbを使用する必要があります。

列をjsonbとして構築する場合は、次のクエリを使用できます。

SELECT * FROM "mytable"
  WHERE blob @> '{"ids": [185603363289694211]}';

@>はPostgresの包含演算子です jsonbについてはここに記載Alain's answer に感謝します。

14
Joe Shaw

最初に、->>ではなく演算子 -> を試して、配列値からJSONレイヤーを削除します。

次に、queryは次のように機能します。
新しいPostgreSQL JSONデータ型内のフィールドを使用してクエリするにはどうすればよいですか?

また、indexingは次のように機能します。
JSON配列で要素を見つけるためのインデックス

5

久しぶりだね...

Postgresql-9.5では、簡単にクエリを実行できるようになりました。

select '{"name": "Wolf",
         "ids": [185603363281305602,185603363289694211]}'::jsonb
       @> '{"ids":[185603363281305602]}'

代わりにjsonbフィールドを使用する必要があり、後でインデックス化できます。

CREATE INDEX idx_gin_ids ON mytable USING gin ((blob -> 'ids'));
4
Alain Gilbert