JSON türü içindeki dizi öğeleri için sorgu


118

jsonPostgreSQL 9.3'teki türü test etmeye çalışıyorum .
Bir var jsondenilen sütun dataadı verilen bir tabloda reports. JSON şuna benzer:

{
  "objects": [
    {"src":"foo.png"},
    {"src":"bar.png"}
  ],
  "background":"background.png"
}

'Objeler' dizisindeki 'src' değeriyle eşleşen tüm raporlar için tabloyu sorgulamak istiyorum. Örneğin, eşleşen tüm raporlar için DB'yi sorgulamak mümkün müdür 'src' = 'foo.png'? Başarıyla eşleşebilecek bir sorgu yazdım "background":

SELECT data AS data FROM reports where data->>'background' = 'background.png'

Fakat "objects"bir dizi değere sahip olduğu için, işe yarayan bir şey yazamıyorum. Eşleşen tüm raporlar için DB'yi sorgulamak mümkün müdür 'src' = 'foo.png'? Bu kaynaklara baktım ama yine de anlayamıyorum:

Ben de bunun gibi şeyleri denedim ama boşuna:

SELECT json_array_elements(data->'objects') AS data from reports
WHERE  data->>'src' = 'foo.png';

SQL uzmanı değilim, bu yüzden neyi yanlış yaptığımı bilmiyorum.

Yanıtlar:


215

json Postgres 9.3+ sürümünde

Yan tümcede json_array_elements()yanal birleşimdeki işlevle JSON dizisinin iç içe geçmişini kaldırın FROMve öğelerini test edin:

WITH reports(data) AS (
   VALUES ('{"objects":[{"src":"foo.png"}, {"src":"bar.png"}]
           , "background":"background.png"}'::json)
   ) 
SELECT *
FROM   reports r, json_array_elements(r.data#>'{objects}') obj
WHERE  obj->>'src' = 'foo.png';

CTE ( WITHsorgu) sadece bir tablo yerine reports.
Veya, yalnızca tek bir yuvalama düzeyi için eşdeğer :

SELECT *
FROM   reports r, json_array_elements(r.data->'objects') obj
WHERE  obj->>'src' = 'foo.png';

->>, ->Ve #>operatörler manuel olarak açıklanmıştır.

Her iki sorgu da örtük kullanır JOIN LATERAL.

SQL Fiddle.

Yakından ilgili cevap:

jsonb Postgres 9.4+ sürümünde

Eşdeğeri kullanın jsonb_array_elements().

Daha da iyisi, yeni "içerir" operatörünü kullanın @>(en iyisi, ifadede eşleşen bir GIN dizini ile kombinasyon halinde data->'objects'):

CREATE INDEX reports_data_gin_idx ON reports
USING gin ((data->'objects') jsonb_path_ops);

SELECT * FROM reports WHERE data->'objects' @> '[{"src":"foo.png"}]';

Anahtar objectsbir JSON dizisi içerdiğinden , arama terimindeki yapıyı eşleştirmemiz ve dizi elemanını da köşeli parantez içine almamız gerekir. Düz bir kayıt ararken dizi parantezlerini bırakın.

Ayrıntılı açıklama ve daha fazla seçenek:


1
@pacothelovetaco: jsonb/ pg 9.4 için bir güncelleme eklendi . Bir kenara: basit durum için (1 seviye yerleştirme), ->operatör aynı zamanda jsonsayfa 9.3'teki hile yapar .
Erwin Brandstetter

1
@pacothelovetaco, sayfa 9.3 için '#>' gizli sos değildir, '->' json nesnesini de döndürdüğü için sizin durumunuz için yeterli olacaktır. '#>', '{}'
Gob00st

1
@> '[{"src": "foo.png"}]'; nerede durumda iyi çalışır, ancak bunun gibi belirli nesneler nasıl silinir? bu nesnenin indeksini bilmiyorum. Anahtar değerine göre silmek istiyorum.
Pranay Soni

1
@PranaySoni: Lütfen yeni soruyu soru olarak sorun . Yorumlar yer değil. Bağlam için her zaman buna bağlanabilirsiniz.
Erwin Brandstetter

sevgili @ErwinBrandstetter, her iki belgeyi de kısmi eşleştirme ile bulmak mümkün mü? Örneğin, '[{"src": ". Png"}]'
Pyrejkee,

8

Json türünde sütun içeren bir tablo oluşturun

CREATE TABLE friends ( id serial primary key, data jsonb);

Şimdi json verilerini ekleyelim

INSERT INTO friends(data) VALUES ('{"name": "Arya", "work": ["Improvements", "Office"], "available": true}');
INSERT INTO friends(data) VALUES ('{"name": "Tim Cook", "work": ["Cook", "ceo", "Play"], "uses": ["baseball", "laptop"], "available": false}');

Şimdi verileri almak için bazı sorgular yapalım

select data->'name' from friends;
select data->'name' as name, data->'work' as work from friends;

Sonuçların ters virgül (") ve köşeli parantez ([]) ile geldiğini fark etmiş olabilirsiniz

    name    |            work            
------------+----------------------------
 "Arya"     | ["Improvements", "Office"]
 "Tim Cook" | ["Cook", "ceo", "Play"]
(2 rows)

Şimdi sadece değerleri almak için sadece kullanın ->>

select data->>'name' as name, data->'work'->>0 as work from friends;
select data->>'name' as name, data->'work'->>0 as work from friends where data->>'name'='Arya';

22
Bu, soruyla farkedilebilir bir bağlantısı olmayan hoş bir şekilde biçimlendirilmiş gürültüdür.
Erwin Brandstetter

4
Bunu yararlı buldum. Bir jsonb'da dizinin nasıl detaylandırılacağını gösterir
GavinBelson

0

veri -> 'nesneler' -> 0 -> 'src' tablodan SRC olarak burada veri -> 'nesneler' -> 0 -> 'src' = 'foo.png'


2
Bu, YALNIZCA 0 olan endeksi biliyorsanız faydalı olacaktır.
Buyut Joko Rivai

evet ama dizi nesnesini patlatmanın, satırı akıllıca eşleştirecek bir yolu var ve bunu kullanabiliriz. Eğer Yanlışsam beni düzelt.
anand shukla

emin olamayacağınız için iyi bir çözüm değil, "src" 0 konumunda.
simUser
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.