2016-09-27 22 views
3

私はJSONBカラムにデータを格納するテーブルを持っています。JSONBデータでPostgresテーブルを照会する

ここでは、そのテーブルをクエリし、キーの特定の値を持つレコードを取得します。

SELECT "documents".* 
FROM "documents" 
WHERE (data @> '{"type": "foo"}') 

をしかし、私は何をしたいタイプfoo OR barを持っているテーブル内のすべての行をフェッチ、次のとおりです。

これが正常に動作します。

私はこの試みた:

SELECT "documents".* 
FROM "documents" 
WHERE (data @> '{"type": ["foo", "bar"]}') 

をしかし、これは動作するようには思えません。

また、私はこれを試してみました:

SELECT "documents".* 
FROM "documents" 
WHERE (data->'type' ?| array['foo', 'bar']) 

働くが、私はそれは、クエリの動的性を奪うのでdata->'type'のようなキーを指定した場合。

私はRuby on RailsをPostgresで使用していますので、すべてのクエリはActiveRecordです。それは、クエリの動的性を奪う>「型」 - 私は、データのようなキーを指定した場合

Document.where("data @> ?", query) 

答えて

3

:これはどのようにあります。

は、私はあなたがこのように定義された列data上GINインデックスを持って理解してくださいではなく、この1のための

EXPLAIN ANALYSE 
SELECT "documents".* 
FROM "documents" 
WHERE data @> '{"type": "foo"}'; 

                  QUERY PLAN               
------------------------------------------------------------------------------------------------------------------------------ 
Bitmap Heap Scan on documents (cost=30.32..857.00 rows=300 width=25) (actual time=0.639..0.640 rows=1 loops=1) 
    Recheck Cond: (data @> '{"type": "foo"}'::jsonb) 
    Heap Blocks: exact=1 
    -> Bitmap Index Scan on documents_data_idx (cost=0.00..30.25 rows=300 width=0) (actual time=0.581..0.581 rows=1 loops=1) 
     Index Cond: (data @> '{"type": "foo"}'::jsonb) 
Planning time: 7.928 ms 
Execution time: 0.841 ms 

インデックスは、このクエリのために働く

CREATE INDEX ON documents USING GIN (data); 

EXPLAIN ANALYSE 
SELECT "documents".* 
FROM "documents" 
WHERE (data->'type' ?| array['foo', 'bar']); 

               QUERY PLAN             
----------------------------------------------------------------------------------------------------------- 
Seq Scan on documents (cost=0.00..6702.98 rows=300 width=25) (actual time=31.895..92.813 rows=2 loops=1) 
    Filter: ((data -> 'type'::text) ?| '{foo,bar}'::text[]) 
    Rows Removed by Filter: 299997 
Planning time: 1.836 ms 
Execution time: 92.839 ms 

解決策1. opを使用しますerator @>二回、インデックスは両方の条件のために使用されます。

CREATE INDEX ON documents USING GIN ((data->'type')); 

EXPLAIN ANALYSE 
SELECT "documents".* 
FROM "documents" 
WHERE (data->'type' ?| array['foo', 'bar']); 

                  QUERY PLAN               
------------------------------------------------------------------------------------------------------------------------------ 
Bitmap Heap Scan on documents (cost=30.32..857.75 rows=300 width=25) (actual time=0.056..0.067 rows=2 loops=1) 
    Recheck Cond: ((data -> 'type'::text) ?| '{foo,bar}'::text[]) 
    Heap Blocks: exact=2 
    -> Bitmap Index Scan on documents_expr_idx (cost=0.00..30.25 rows=300 width=0) (actual time=0.035..0.035 rows=2 loops=1) 
     Index Cond: ((data -> 'type'::text) ?| '{foo,bar}'::text[]) 
Planning time: 2.951 ms 
Execution time: 0.108 ms 

ソリューション3.これは解決策1の変形である事実:

EXPLAIN ANALYSE 
SELECT "documents".* 
FROM "documents" 
WHERE data @> '{"type": "foo"}' 
OR data @> '{"type": "bar"}'; 

                  QUERY PLAN                
------------------------------------------------------------------------------------------------------------------------------------ 
Bitmap Heap Scan on documents (cost=60.80..1408.13 rows=600 width=25) (actual time=0.222..0.233 rows=2 loops=1) 
    Recheck Cond: ((data @> '{"type": "foo"}'::jsonb) OR (data @> '{"type": "bar"}'::jsonb)) 
    Heap Blocks: exact=2 
    -> BitmapOr (cost=60.80..60.80 rows=600 width=0) (actual time=0.204..0.204 rows=0 loops=1) 
     -> Bitmap Index Scan on documents_data_idx (cost=0.00..30.25 rows=300 width=0) (actual time=0.144..0.144 rows=1 loops=1) 
       Index Cond: (data @> '{"type": "foo"}'::jsonb) 
     -> Bitmap Index Scan on documents_data_idx (cost=0.00..30.25 rows=300 width=0) (actual time=0.059..0.059 rows=1 loops=1) 
       Index Cond: (data @> '{"type": "bar"}'::jsonb) 
Planning time: 3.170 ms 
Execution time: 0.289 ms 

ソリューション2. (data->'type')に追加のインデックスを作成します。 、クライアントプログラムで使用する方が便利かもしれ条件の異なるフォーマットで:

​​

the documentationで詳細をお読みください。

+0

応答@klinありがとうございます。ソリューション1は動作しますが、私は他の方法を考えていました.RailsはAPIの一部であり、何らかの要求があり、paramsを解析する必要はありません。これは基本的な操作なので、そこにいるはずのクリーナーな方法を考えていました。どう思いますか? –

+0

私はあなたが何を意味しているのか知っています。それが私が2番目の解決策について書いた理由です。クリーナーはありません。 – klin

+0

ええ、属性は変更できますが、必ずしも型になるとは限りません。したがって、構文解析が行われます。 –

関連する問題