PostgreSQL परिणाम JSON सरणी के रूप में सेट करें?


134

मैं चाहता हूँ कि PostgreSQL एक JSON सरणी के रूप में एक क्वेरी का परिणाम लौटाए। दिया हुआ

create table t (a int primary key, b text);

insert into t values (1, 'value1');
insert into t values (2, 'value2');
insert into t values (3, 'value3');

मैं भी कुछ ऐसा ही चाहूंगा

[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]

या

{"a":[1,2,3], "b":["value1","value2","value3"]}

(वास्तव में दोनों को जानना अधिक उपयोगी होगा)। मैंने कुछ चीजों की कोशिश की है जैसे

select row_to_json(row) from (select * from t) row;
select array_agg(row) from (select * from t) row;
select array_to_string(array_agg(row), '') from (select * from t) row;

और मुझे लगता है कि मैं करीब हूं, लेकिन वास्तव में वहां नहीं है। क्या मुझे 9.15 को छोड़कर अन्य दस्तावेज़ीकरण को देखना चाहिए। JSON फ़ंक्शंस और ऑपरेटर्स ?

वैसे, मुझे अपने विचार पर यकीन नहीं है। क्या यह एक सामान्य डिजाइन निर्णय है? मेरी सोच यह है कि मैं, निश्चित रूप से उपरोक्त 3 प्रश्नों में से पहले का परिणाम (उदाहरण के लिए) ले सकता हूं और इसे क्लाइंट को सेवा देने से पहले आवेदन में थोड़ा हेरफेर कर सकता हूं, लेकिन अगर पोस्टग्रेक्यूएल अंतिम JSON ऑब्जेक्ट को सीधे बना सकता है, तो यह सरल होगा, क्योंकि मैंने अभी भी अपने आवेदन में किसी JSON लाइब्रेरी पर निर्भरता को शामिल नहीं किया है।


1
पीजी 9.4, जो अब बीटा 1 रिलीज में उपलब्ध है, ने JSON के लिए द्विआधारी I / O सहित समर्थन में सुधार किया है। यदि आप एक विकास मशीन पर हैं तो आप इसे जांचना चाहते हैं।
पैट्रिक

@Patrick: धन्यवाद, यह json_object की तरह दिखता है () 9.4 में एक नया फ़ंक्शन है और मैं कुछ चुनता हूँ जैसे SELECT json_object (array_agg (ta), array_agg (tb)) FROM t, अगर मेरे पास था
इंजीनियरएक्स

जवाबों:


266

टी एल; डॉ

SELECT json_agg(t) FROM t

वस्तुओं के JSON सरणी के लिए, और

SELECT
    json_build_object(
        'a', json_agg(t.a),
        'b', json_agg(t.b)
    )
FROM t

सरणियों के JSON ऑब्जेक्ट के लिए।

वस्तुओं की सूची

यह खंड बताता है कि वस्तुओं के JSON सरणी को कैसे उत्पन्न किया जाए, प्रत्येक पंक्ति को एक वस्तु में परिवर्तित किया जाए। परिणाम इस तरह दिखता है:

[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]

9.3 और ऊपर

json_aggसमारोह बॉक्स से बाहर इस परिणाम पैदा करता है। यह स्वचालित रूप से यह पता लगाता है कि इसके इनपुट को JSON में कैसे परिवर्तित किया जाए और इसे एक सरणी में संयोजित किया जाए।

SELECT json_agg(t) FROM t

कोई jsonb(9.4 में पेश) संस्करण है json_agg। आप या तो पंक्तियों को एक सरणी में जोड़ सकते हैं और फिर उन्हें परिवर्तित कर सकते हैं:

SELECT to_jsonb(array_agg(t)) FROM t

या json_aggएक कलाकार के साथ गठबंधन :

SELECT json_agg(t)::jsonb FROM t

मेरा परीक्षण बताता है कि पहले उन्हें एक सरणी में एकत्र करना थोड़ा तेज है। मुझे संदेह है कि ऐसा इसलिए है क्योंकि कलाकारों को पूरे JSON परिणाम को पार्स करना है।

9.2

9.2 में json_aggया to_jsonकार्य नहीं है , इसलिए आपको पुराने का उपयोग करने की आवश्यकता है array_to_json:

SELECT array_to_json(array_agg(t)) FROM t

आप वैकल्पिक रूप row_to_jsonसे क्वेरी में एक कॉल शामिल कर सकते हैं :

SELECT array_to_json(array_agg(row_to_json(t))) FROM t

यह प्रत्येक पंक्ति को JSON ऑब्जेक्ट में कनवर्ट करता है, JSON ऑब्जेक्ट्स को एक सरणी के रूप में एकत्रित करता है, और फिर सरणी को JSON सरणी में कनवर्ट करता है।

मैं दोनों के बीच किसी भी महत्वपूर्ण प्रदर्शन अंतर को समझने में सक्षम नहीं था।

सूचियों का उद्देश्य

यह खंड बताता है कि एक JSON ऑब्जेक्ट कैसे उत्पन्न होता है, जिसमें प्रत्येक कुंजी तालिका में एक स्तंभ है और प्रत्येक मान स्तंभ के मानों की एक सरणी है। यह परिणाम है कि इस तरह दिखता है:

{"a":[1,2,3], "b":["value1","value2","value3"]}

9.5 और ऊपर

हम json_build_objectसमारोह का लाभ उठा सकते हैं :

SELECT
    json_build_object(
        'a', json_agg(t.a),
        'b', json_agg(t.b)
    )
FROM t

आप एकल पंक्ति बनाते हुए, स्तंभों को भी एकत्र कर सकते हैं और फिर उसे एक वस्तु में बदल सकते हैं:

SELECT to_json(r)
FROM (
    SELECT
        json_agg(t.a) AS a,
        json_agg(t.b) AS b
    FROM t
) r

ध्यान दें कि एरे को अलियास करना यह सुनिश्चित करने के लिए आवश्यक है कि ऑब्जेक्ट में वांछित नाम हैं।

कौन सा स्पष्ट है यह राय का विषय है। अगर का उपयोग करjson_build_object फ़ंक्शन रहा है, तो मैं पठनीयता में सुधार करने के लिए एक पंक्ति पर एक कुंजी / मूल्य जोड़ी लगाने की अत्यधिक सलाह देता हूं।

आप के array_aggस्थान पर भी उपयोग कर सकते हैं json_agg, लेकिन मेरा परीक्षण इंगित करता है कि json_aggथोड़ा तेज है।

फ़ंक्शन का कोई jsonbसंस्करण नहीं है json_build_object। आप एक पंक्ति में एकत्र कर सकते हैं और परिवर्तित कर सकते हैं:

SELECT to_jsonb(r)
FROM (
    SELECT
        array_agg(t.a) AS a,
        array_agg(t.b) AS b
    FROM t
) r

इस तरह के परिणाम के लिए अन्य प्रश्नों के विपरीत, array_aggउपयोग करते समय थोड़ा तेज लगता है to_jsonb। मुझे संदेह है कि यह ओवरहेड पार्सिंग और JSON परिणाम को मान्य करने के कारण है json_agg

या आप एक स्पष्ट कलाकारों का उपयोग कर सकते हैं:

SELECT
    json_build_object(
        'a', json_agg(t.a),
        'b', json_agg(t.b)
    )::jsonb
FROM t

to_jsonbसंस्करण मेरी परीक्षण के अनुसार, आप कलाकारों से बचने के लिए अनुमति देता है और तेजी से होता है; फिर से, मुझे संदेह है कि यह पार्सिंग के ओवरहेड और परिणाम को मान्य करने के कारण है।

9.4 और 9.3

json_build_objectसमारोह 9.5 के लिए नया था, तो आप पिछले संस्करणों में एक वस्तु को समग्र और परिवर्तित करने के लिए है:

SELECT to_json(r)
FROM (
    SELECT
        json_agg(t.a) AS a,
        json_agg(t.b) AS b
    FROM t
) r

या

SELECT to_jsonb(r)
FROM (
    SELECT
        array_agg(t.a) AS a,
        array_agg(t.b) AS b
    FROM t
) r

आप चाहते हैं jsonया पर निर्भर करता है jsonb

(9.3 नहीं है jsonb)

9.2

9.2 में भी to_jsonमौजूद नहीं है। आप का उपयोग करना चाहिए row_to_json:

SELECT row_to_json(r)
FROM (
    SELECT
        array_agg(t.a) AS a,
        array_agg(t.b) AS b
    FROM t
) r

प्रलेखन

JSON फ़ंक्शन में JSON फ़ंक्शन के लिए दस्तावेज़ ढूँढें ।

json_aggपर है सकल कार्यों पेज।

डिज़ाइन

यदि प्रदर्शन महत्वपूर्ण है, तो सुनिश्चित करें कि आप मेरे परीक्षण के बजाय अपने स्वयं के स्कीमा और डेटा के खिलाफ अपने प्रश्नों को चिह्नित करें।

यह एक अच्छा डिज़ाइन है या नहीं यह वास्तव में आपके विशिष्ट एप्लिकेशन पर निर्भर करता है। स्थिरता के संदर्भ में, मुझे कोई विशेष समस्या नहीं दिख रही है। यह आपके ऐप कोड को सरल बनाता है और इसका मतलब है कि ऐप के उस हिस्से को बनाए रखना कम है। यदि पीजी आपको बिल्कुल सही परिणाम दे सकता है, तो आपको बॉक्स से बाहर की जरूरत है, केवल एक ही कारण है कि मैं इसका उपयोग नहीं करने के बारे में सोच सकता हूं। पहिया और सभी को सुदृढ़ न करें।

nulls

NULLजब वे शून्य पंक्तियों पर काम करते हैं, तो एग्रीगेट फ़ंक्शंस आमतौर पर वापस आ जाते हैं। यदि यह एक संभावना है, तो आप COALESCEउनसे बचने के लिए उपयोग करना चाह सकते हैं । कुछ उदाहरण:

SELECT COALESCE(json_agg(t), '[]'::json) FROM t

या

SELECT to_jsonb(COALESCE(array_agg(t), ARRAY[]::t[])) FROM t

करने के लिए क्रेडिट हैनेस Landeholm के लिए इस ओर इशारा करते हुए


3
आपके उत्तर के लिए धन्यवाद। आपने मुझे मेरे दूसरे प्रश्न का उत्तर खोजने के लिए प्रेरित किया, SELECT row_to_json (पंक्ति (array_agg (ta), array_agg (tb))) से F, हालांकि परिणाम में "f1" और "f2" लेबल के बजाय a और b हैं।
इंजीनियरएक्स

@engineerX मैंने अपने उत्तर का विस्तार किया है।
jpmc26

3
यह कुछ मामलों में अवांछनीय हो सकता है जब खाली JSON सरणी के बजाय NULL वापस मिलता है जब आंतरिक चयन (t से) शून्य पंक्तियाँ देता है। यह कुल कार्यों के कारण होता है, हमेशा NULL को लौटते समय, जब कोई पंक्तियों का चयन नहीं होता है और coalesce द्वारा हल किया जा सकता है: array_to_json (coalesce (array_agg (t), array [] :: record []))।
हेंस लैंडेहोम

3
आप to_jsonइसके बजाय row_to_jsonऔर इसका उपयोग कर सकते हैं array_to_json
18

(एकाधिक) विशिष्ट स्तंभों का चयन करने के लिए, आपको उन्हें एक ही तर्क के रूप में पास करना होगा - एक गोल ब्रैकेट सूची जैसे SELECT json_agg((column1, column2, ...)) FROM t - अतिरिक्त कोष्ठक पर ध्यान दें। यह स्पष्ट नहीं हो सकता है "बॉक्स से बाहर"।
jave.web

19

इसके अलावा, यदि आप तालिका से चयनित फ़ील्ड चाहते हैं और फिर एरे के रूप में एकत्रित हैं।

SELECT json_agg(json_build_object('data_a',a,
                                  'data_b',b,
))  from t;

रिजल्ट आएगा।

 [{'data_a':1,'data_b':'value1'}
  {'data_a':2,'data_b':'value2'}]
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.