web-dev-qa-db-ja.com

JSONタイプ内の配列要素のクエリ

PostgreSQL 9.3でjson型をテストしようとしています。
jsonというテーブルにdataというreports列があります。 JSONは次のようになります。

{
  "objects": [
    {"src":"foo.png"},
    {"src":"bar.png"}
  ],
  "background":"background.png"
}

'objects'配列の 'src'値に一致するすべてのレポートのテーブルを照会したいと思います。たとえば、'src' = 'foo.png'に一致するすべてのレポートについてDBにクエリを実行できますか? "background"に一致するクエリを作成しました:

SELECT data AS data FROM reports where data->>'background' = 'background.png'

しかし、"objects"には値の配列があるため、動作する何かを書くことはできないようです。 'src' = 'foo.png'に一致するすべてのレポートをDBに照会することは可能ですか?これらのソースを調べましたが、まだ取得できません。

私もこのようなことを試しましたが、役に立ちませんでした:

SELECT json_array_elements(data->'objects') AS data from reports
WHERE  data->>'src' = 'foo.png';

私はSQLの専門家ではないので、何が間違っているのかわかりません。

83
pacothelovetaco

Postgres 9.3以降のjson

FROM句のラテラル結合で関数 json_array_elements() を使用してJSON配列のネストを解除し、その要素をテストします。

WITH reports(data) AS (
   VALUES ('{"objects":[{"src":"foo.png"}, {"src":"bar.png"}]
           , "background":"background.png"}'::json)
   ) 
SELECT *
FROM   reports r, json_array_elements(r.data#>'{objects}') obj
WHERE  obj->>'src' = 'foo.png';

CTEWITH query)は、テーブルreportsの代わりになります。
または、単一レベルのネスティングと同等:

SELECT *
FROM   reports r, json_array_elements(r.data->'objects') obj
WHERE  obj->>'src' = 'foo.png';

->>->#>演算子はマニュアルで説明されています。

両方のクエリは暗黙的な JOIN LATERAL を使用します。

SQL Fiddle。

密接に関連した答え:

Postgres 9.4以降のjsonb

同等の jsonb_array_elements() を使用します。

Betterまだ、新しい「含む」演算子@>を使用します(式data->'objects'の一致するGINインデックスとの組み合わせが最適です)。

CREATE INDEX reports_data_gin_idx ON reports
USING gin ((data->'objects') jsonb_path_ops);

SELECT * FROM reports WHERE data->'objects' @> '[{"src":"foo.png"}]';

キーobjectsはJSONarrayを保持しているため、検索語の構造と一致し、配列要素も角括弧で囲む必要があります。プレーンレコードを検索するときに配列の角かっこを削除します。

詳細な説明とその他のオプション:

160

タイプjsonとして列を持つテーブルを作成します

# CREATE TABLE friends ( id serial primary key, data jsonb);

では、jsonデータを挿入しましょう

# INSERT INTO friends(data) VALUES ('{"name": "Arya", "work": ["Improvements", "Office"], "available": true}');

# INSERT INTO friends(data) VALUES ('{"name": "Tim Cook", "work": ["Cook", "ceo", "Play"], "uses": ["baseball", "laptop"], "available": false}');

次に、データを取得するためのクエリを作成しましょう

# select data->'name' from friends;

# select data->'name' as name, data->'work' as work from friends;

結果に逆コンマ( ")と角括弧([])が付いていることに気づいたかもしれません

    name    |            work            
------------+----------------------------
 "Arya"     | ["Improvements", "Office"]
 "Tim Cook" | ["Cook", "ceo", "Play"]
(2 rows)

値のみを取得するには、->>を使用します

# select data->>'name' as name, data->'work'->>0 as work from friends;

#select data->>'name' as name, data->'work'->>0 as work from friends where data->>'name'='Arya';
3
Sandip Debnath