PostgreSQLのjsonb配列から特定のオブジェクトを取得するにはどうすればよいですか?


15

おおよそ次のようなjson配列を保持する「user」というフィールドがあります。

"user"

[{ "_id" : "1", "count" : "4" }, { "_id" : "3", "count": "4"}]

今私は次のようなクエリが必要です:

select count from tablename where id = "1"

countPostgreSQL 9.4では、jsonオブジェクトの配列から特定のフィールドを取得できません。

回答:


17

正規化されたスキーマに値を格納する方がはるかに効率的です。つまり、現在の設定で動作させることもできます。

仮定

このテーブル定義を仮定すると:

CREATE TABLE tbl (tbl_id int, usr jsonb);

「user」は予約語であり、列名として使用するには二重引用符が必要です。それをしないでください。usr代わりに使用します。

クエリ

クエリは、(現在は削除されている)コメントのように簡単ではありません。

SELECT t.tbl_id, obj.val->>'count' AS count
FROM   tbl t
JOIN   LATERAL jsonb_array_elements(t.usr) obj(val) ON obj.val->>'_id' = '1'
WHERE  t.usr @> '[{"_id":"1"}]';

3つの基本的な手順があります

1.適格な行を安価に識別する

WHERE t.usr @> '[{"_id":"1"}]'JSON配列内の一致するオブジェクトを持つ行を識別します。式では、jsonb列で一般的なGINインデックスを使用することも、より特殊な演算子クラスを使用することもできますjsonb_path_ops

CREATE INDEX tbl_usr_gin_idx ON tbl USING gin (usr jsonb_path_ops);

追加されたWHERE句は論理的に冗長ですが、インデックスを使用する必要があります。結合句の式は同じ条件を適用しますが、これまでに条件を満たしているすべての行で配列のネストを解除した後でのみです。インデックスのサポートにより、Postgresは、最初に適格オブジェクトを含む行のみを処理します。たいした小さなテーブルと、なりません巨大な大きなテーブルとわずか数条件を満たす行との違いを。

関連:

2.配列内の一致するオブジェクトを特定する

とのネストを解除しjsonb_array_elements()ます。(unnest()Postgres配列型にのみ有効です。)実際に一致するオブジェクトのみに関心があるため、すぐに結合条件でフィルタリングします。

関連:

3.ネストされたキーの値を抽出する 'count'

適格なオブジェクトが抽出された後、単に:obj.val->>'count'


2
どこobj(value)から来たのですか?それは上にあるLATERAL JOINjsonb_array_elementsまたは他のどこか?
タイラー・デウィット

書式がめちゃくちゃになっているようです。私はそれを正しく読んでいますか?JOIN LATERAL jsonb_array_elements(t.usr) obj(value) is short for JOIN LATERAL jsonb_array_elements(t.usr) AS obj(value)それobj(value)はテーブルと列のエイリアスですか?この例でobjは、テーブルエイリアスの場合、それは何のエイリアスですか?セットから返されましたかjsonb_array_elements
タイラー・デウィット

1
はい、そしてはい。スクランブルコメントを削除しました。
Erwin Brandstetter

列のエイリアスを使用する必要はありますか?私のテストでJOIN LATERAL jsonb_array_elements(t.usr) obj ON obj->>'_id' = '1'は、同じ効果がありました(selectステートメントを更新して、のvalue代わりに使用した場合val)。それが表示されますjsonb_array_elements(t.usr)1つの列のみを持つテーブルを返します。postgresは賢くobj ->>、それと同じことを実現していobj.val ->>ますか?
タイラーデウィット

列が1つだけの場合、Postgresはテーブル列の名前として特定のエイリアスを使用します。2つ以上の列を返す多くのセットを返す関数があるので、私は明示的にしています。
Erwin Brandstetter
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.