JSON प्रकार के अंदर सरणी तत्वों के लिए क्वेरी


118

मैं jsonPostgreSQL 9.3 में प्रकार का परीक्षण करने की कोशिश कर रहा हूं ।
मेरे पास एक jsonस्तंभ है जिसे dataएक तालिका में बुलाया जाता है reports। JSON कुछ इस तरह दिखता है:

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

मैं उन सभी रिपोर्टों के लिए तालिका को क्वेरी करना चाहूंगा जो 'ऑब्जेक्ट्स' एरे में 'src' मान से मेल खाती हैं। उदाहरण के लिए, क्या उन सभी रिपोर्टों के लिए DB को क्वेरी करना संभव है जो मेल खाते हैं 'src' = 'foo.png'? मैंने सफलतापूर्वक एक क्वेरी लिखी है जो मेल कर सकती है "background":

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

लेकिन चूंकि "objects"मानों की एक सरणी है, इसलिए मैं कुछ ऐसा नहीं लिख सकता जो काम करता है। क्या मैच से संबंधित सभी रिपोर्टों के लिए DB को क्वेरी करना संभव है 'src' = 'foo.png'? मैंने इन स्रोतों को देखा है लेकिन फिर भी इसे प्राप्त नहीं कर सकता:

मैंने भी इस तरह की चीजों की कोशिश की है लेकिन कोई फायदा नहीं हुआ:

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

मैं एक SQL विशेषज्ञ नहीं हूं, इसलिए मुझे नहीं पता कि मैं क्या गलत कर रहा हूं।

जवाबों:


215

json पोस्टग्रैड्स 9.3+ में

json_array_elements()एक पार्श्व में फ़ंक्शन के साथ JSON सरणी को अनजाने करें जो FROMक्लॉज में शामिल हो और इसके तत्वों के लिए परीक्षण करें:

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 ( WITHक्वेरी) सिर्फ एक मेज के लिए विकल्प reports
या, बस एक के लिए बराबर ही घोंसले का स्तर:

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

->>, ->और #>ऑपरेटरों को मैनुअल में समझाया गया है।

दोनों प्रश्न एक निहित का उपयोग करते हैं JOIN LATERAL

एसक्यूएल फिडल।

बारीकी से संबंधित जवाब:

jsonb Postgres में 9.4+

समकक्ष का उपयोग करें jsonb_array_elements()

बेहतर अभी तक, नए "समाहित" ऑपरेटर का उपयोग करें @>(अभिव्यक्ति पर मिलान GIN सूचकांक के साथ संयोजन में सर्वश्रेष्ठ 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"}]';

चूंकि कुंजी objectsJSON सरणी रखती है , इसलिए हमें खोज शब्द में संरचना से मेल खाना चाहिए और सरणी तत्व को वर्ग कोष्ठक में भी लपेटना चाहिए। एक सादे रिकॉर्ड खोजते समय सरणी कोष्ठक गिराएं।

विस्तृत विवरण और अधिक विकल्प:


1
@pacothelovetaco: ने jsonb/ pg 9.4 के लिए एक अपडेट जोड़ा । एक तरफ: साधारण मामले (घोंसले के शिकार के स्तर) के लिए, ->ऑपरेटर json9.3 पीजी के लिए चाल भी करता है ।
एरविन ब्रैंडस्टैटर

1
@pacothelovetaco, pg 9.3 के लिए, '#>' सीक्रेट सॉस नहीं है, '->' आपके केस के लिए ठीक होगा क्योंकि यह भी json objec लौटाता है। नेस्टेड जोंस पाथ केस में '#>' ज्यादा मददगार होगा क्योंकि इससे आप आसानी से '{}' में पथ निर्दिष्ट कर सकते हैं
Gob00st

1
@> '[{"src": "foo.png"}]'; किस हालत में ठीक काम करते हैं लेकिन इस तरह विशेष वस्तु को कैसे हटाएं? मैं इस वस्तु का सूचकांक नहीं जानता। मैं प्रमुख मूल्य से हटाना चाहता हूँ।
प्रणय सोनी

1
@PranaySoni: कृपया नए प्रश्न को प्रश्न के रूप में पूछें । टिप्पणियाँ जगह नहीं हैं। आप संदर्भ के लिए इसे हमेशा लिंक कर सकते हैं।
एरविन ब्रान्डस्टेट्टर

प्रिय @ErwinBrandstetter, क्या आंशिक मिलान द्वारा दोनों दस्तावेजों को ढूंढना संभव है? उदाहरण के लिए, मैं दोनों रिकॉर्ड कुछ इस तरह से प्राप्त करना चाहूंगा कि '[{"src": "। Png"}]'
Pyrejkee

8

टाइप json के रूप में कॉलम के साथ एक तालिका बनाएँ

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

अब आप json data डालें

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}');

अब डेटा लाने के लिए कुछ क्वेरी करें

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

आपने देखा होगा कि परिणाम उल्टे अल्पविराम (") और कोष्ठक ([]) के साथ आते हैं।

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

अब केवल मूल्यों का उपयोग करने के लिए ->>

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
यह सुखद रूप से स्वरूपित शोर है जो प्रश्न के लिए समझ में नहीं आता है।
एरविन ब्रान्डसेट्टर

4
मुझे यह उपयोगी लगा। दिखाता है कि कैसे एक jsonb में सरणी में ड्रिल करने के लिए
GavinBelson

0

डेटा का चयन करें -> 'ऑब्जेक्ट' -> 0 -> 'src' SRC के रूप में टेबल से जहाँ डेटा -> 'ऑब्जेक्ट' -> 0 -> 'src' = 'foo.png'


2
यह केवल
तभी

हाँ, लेकिन एरे ऑब्जेक्ट को विस्फोट करने का एक तरीका है जो पंक्तिवार मैप करेगा और हम इसका उपयोग कर सकते हैं। अगर मैं ग़लत हूं तो मेरी गलती सुझाएं।
आनंद शुक्ला

एक अच्छा समाधान नहीं है जैसा कि आप सुनिश्चित नहीं कर सकते हैं, "src" स्थिति 0.
simUser
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.