2016-09-27 110 views
3

我有在JSONB列存儲的數據的表。查詢表的Postgres與JSONB數據

現在,我想要做的是,查詢該表,並獲取記錄,其中有一個關鍵的具體數值。

這工作得很好:

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'關鍵它帶走查詢的動態性。

順便說一句,我使用在Postgres Rails的Ruby的,所以所有的查詢都經歷ActiveRecord。這就是:

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

回答

3

如果我指定像這樣的數據的關鍵 - >「類型」它帶走查詢的動態性。

我明白你有這樣定義的列data杜松子酒指數:

CREATE INDEX ON documents USING GIN (data); 

該指數適用於這個查詢:

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 

但不是這一個:

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愛適易@>兩次,索引將被用於這兩個條件:

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')一個附加的索引:

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的一個變體,條件的不同的格式,其可以是由客戶端程序,使用更方便:

​​

更多在the documentation

+0

謝謝你的迴應@klin。解決方案1可以工作,但我想的是其他方式,因爲Rails是API的一部分,並且可以有任何請求,我不想進入解析參數。所以想到了一些更乾淨的方式,我覺得應該在那裏,因爲這只是一個基本的操作。你怎麼看? –

+0

我知道你的意思,這就是爲什麼我寫了第二個解決方案。沒有更乾淨的一個。 – klin

+0

是的,但屬性可以改變,它不會一直是類型的,所以解析會再次出現。 –