オブジェクトの配列に存在するキーを照会しようとしています。この構造:
column jdata
{"name": "Somedata",
"array": [ {"name":"bla1", "attr": "somevalue"},
{"name":"bla2", "otherdata": "somevalue2"},
{"name":"bla3", "otherdata": "somevalue"}
],
"otherstuff": "stuff"
}
今、私はjdata->'name'
または(jdata->'datetime')::cast
でbtreeを実行します。
また、jdata->'array' @> '[{"name":"bla3"}]'
が本当に魅力的なjson_path_opsを実行します。
私の問題は、attrキーが配列内の任意のオブジェクトにある可能性があることです。キーが存在する場合は、レコードを気にしますが、値はほとんど何でもかまいません。これを照会する方法はありますか?インデックスを付ける方法はありますか? jdata->'array' @> '[{"attr": ?}]'
を実行したいですか、それとも? 'attr'
を内部で使用して配列を作成できますか?
現在、キーをスキャンしてからtrueまたはfalseなどのヘッダーに移動するトリガーを考えています。その後、通常のbtreeが機能します。もっと良い方法はありますか?この値を追加するには、平均的なサイトで約50万件のレコードを編集する必要があります。
方向を教えてください。
その特定のユースケースは、現在(10ページ)組み込み演算子のプレーンインデックスではカバーされていません。
SELECT *
FROM tbl
WHERE EXISTS (
SELECT 1
FROM jsonb_array_elements(jdata->'array') elem
WHERE elem ? 'attr'
);
EXISTS
は、複数の配列要素にキーを含めることができる場合でも、各修飾行を1回必要とするためです。そして、それはより高速です。
しかし、このクエリはインデックスを使用できません。
レコードの指定されたjsonb配列で一意のキーのテキスト配列を生成し、式を単純なIMMUTABLE
関数にラップできます。
CREATE OR REPLACE FUNCTION jsonb_arr_record_keys(jsonb)
RETURNS text[] LANGUAGE sql IMMUTABLE AS
'SELECT ARRAY (
SELECT DISTINCT k
FROM jsonb_array_elements($1) elem, jsonb_object_keys(elem) k
)';
COMMENT ON FUNCTION jsonb_arr_record_keys(jsonb) IS '
Generates text array of unique keys in jsonb array of records.
Fails if any array element is not a record!';
次に、この関数に基づいてGIN式インデックスを作成します。
CREATE INDEX tbl_special_idx ON tbl USING gin (jsonb_arr_record_keys(jdata->'array'));
このようなクエリは、ジェネリック配列を使用して、演算子@>
を含みます。
SELECT *
FROM tbl
WHERE jsonb_arr_record_keys(jdata->'array') @> '{attr}';
これで、インデックスを効率的に使用できます。
配列にネストされたキー名を提供します('{attr}'
)。 (この方法で複数のキーを簡単にチェックできます('{attr1, attr2}'
)または同様...)
dbfiddle ここ
関連:
インデックスを付ける方法はありますか?
はい、ただし、PostgreSQLはそのようなJSON配列を使用できないため、構造を簡略化する関数を作成する必要があります。次に、その関数にインデックスを付けることができます。