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.