web-dev-qa-db-ja.com

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

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

"user"

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

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

select count from tablename where id = "1"

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

15
Rabi C Shah

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

仮定

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

_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は、最初から適格オブジェクトを含む行のみを処理します。小さなテーブルではあまり問題にならず、大きなテーブルとhugeの違いがあり、適格な行はほとんどありません。

関連:

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

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

関連:

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

対象となるオブジェクトが抽出された後は、単純に_obj.val->>'count'_です。

17