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の専門家ではないので、何が間違っているのかわかりません。
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';
CTE (WITH
query)は、テーブルreports
の代わりになります。
または、単一レベルのネスティングと同等:
SELECT *
FROM reports r, json_array_elements(r.data->'objects') obj
WHERE obj->>'src' = 'foo.png';
両方のクエリは暗黙的な JOIN LATERAL
を使用します。
密接に関連した答え:
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を保持しているため、検索語の構造と一致し、配列要素も角括弧で囲む必要があります。プレーンレコードを検索するときに配列の角かっこを削除します。
詳細な説明とその他のオプション:
タイプ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';