मैं नए PostgreSQL JSON डेटाटाइप के अंदर फ़ील्ड कैसे संशोधित करूं?


235

Postgresql 9.3 के साथ मैं एक JSON डेटा प्रकार के विशिष्ट क्षेत्रों का चयन कर सकता हूं, लेकिन आप उन्हें UPDATE का उपयोग करके कैसे संशोधित कर सकते हैं? मुझे इसका कोई उदाहरण पोस्टग्रैसक्यूल डॉक्यूमेंटेशन में, या कहीं भी ऑनलाइन नहीं मिल सकता है। मैंने स्पष्ट करने की कोशिश की है:

postgres=# create table test (data json);
CREATE TABLE
postgres=# insert into test (data) values ('{"a":1,"b":2}');
INSERT 0 1
postgres=# select data->'a' from test where data->>'b' = '2';
 ?column?
----------
 1
(1 row)
postgres=# update test set data->'a' = to_json(5) where data->>'b' = '2';
ERROR:  syntax error at or near "->"
LINE 1: update test set data->'a' = to_json(5) where data->>'b' = '2...

जवाबों:


331

अद्यतन : PostgreSQL 9.5 के साथ, PostgreSQL केjsonb भीतर कुछ हेरफेर कार्यक्षमता हैं (लेकिन मूल्यों के साथ jsonछेड़छाड़ करने के लिए कलाकारों की आवश्यकता नहीं है json)।

2 (या अधिक) JSON ऑब्जेक्ट्स को जोड़ना (या संक्षिप्त सारणी):

SELECT jsonb '{"a":1}' || jsonb '{"b":2}', -- will yield jsonb '{"a":1,"b":2}'
       jsonb '["a",1]' || jsonb '["b",2]'  -- will yield jsonb '["a",1,"b",2]'

तो, एक साधारण कुंजी सेट करके प्रयोग किया जा सकता है:

SELECT jsonb '{"a":1}' || jsonb_build_object('<key>', '<value>')

जहां <key>स्ट्रिंग होना चाहिए, और <value>जो भी प्रकार to_jsonb()स्वीकार हो सकता है ।

JSON पदानुक्रम में गहरी मान सेट करने के लिए , jsonb_set()फ़ंक्शन का उपयोग किया जा सकता है:

SELECT jsonb_set('{"a":[null,{"b":[]}]}', '{a,1,b,0}', jsonb '{"c":3}')
-- will yield jsonb '{"a":[null,{"b":[{"c":3}]}]}'

पूर्ण पैरामीटर सूची jsonb_set():

jsonb_set(target         jsonb,
          path           text[],
          new_value      jsonb,
          create_missing boolean default true)

pathJSON सरणी अनुक्रमणिका को भी शामिल कर सकते हैं और नकारात्मक पूर्णांक जो JSON सरणियों के अंत से गिनती में दिखाई देते हैं। हालाँकि, गैर-मौजूदा, लेकिन पॉजिटिव JSON एरे इंडेक्स तत्व को एरे के अंत में जोड़ देगा:

SELECT jsonb_set('{"a":[null,{"b":[1,2]}]}', '{a,1,b,1000}', jsonb '3', true)
-- will yield jsonb '{"a":[null,{"b":[1,2,3]}]}'

JSON सरणी में डालने के लिए (सभी मूल मूल्यों को संरक्षित करते हुए) , jsonb_insert()फ़ंक्शन का उपयोग किया जा सकता है ( 9.6+ में; यह फ़ंक्शन केवल, इस खंड में ):

SELECT jsonb_insert('{"a":[null,{"b":[1]}]}', '{a,1,b,0}', jsonb '2')
-- will yield jsonb '{"a":[null,{"b":[2,1]}]}', and
SELECT jsonb_insert('{"a":[null,{"b":[1]}]}', '{a,1,b,0}', jsonb '2', true)
-- will yield jsonb '{"a":[null,{"b":[1,2]}]}'

पूर्ण पैरामीटर सूची jsonb_insert():

jsonb_insert(target       jsonb,
             path         text[],
             new_value    jsonb,
             insert_after boolean default false)

फिर से, नकारात्मक पूर्णांक जो pathJSON सरणियों के अंत से गिनती में दिखाई देते हैं।

तो, एफ.एक्स। एक JSON सरणी के अंत में आवेदन किया जा सकता है:

SELECT jsonb_insert('{"a":[null,{"b":[1,2]}]}', '{a,1,b,-1}', jsonb '3', true)
-- will yield jsonb '{"a":[null,{"b":[1,2,3]}]}', and

हालांकि, इस समारोह थोड़ा अलग ढंग से (से काम कर रहा है jsonb_set()) जब pathमें targetएक JSON ऑब्जेक्ट के लिए महत्वपूर्ण है। उस स्थिति में, यह केवल JSON ऑब्जेक्ट के लिए एक नया कुंजी-मूल्य जोड़ी जोड़ देगा जब कुंजी का उपयोग नहीं किया जाता है। यदि इसका उपयोग किया जाता है, तो यह एक त्रुटि उत्पन्न करेगा:

SELECT jsonb_insert('{"a":[null,{"b":[1]}]}', '{a,1,c}', jsonb '[2]')
-- will yield jsonb '{"a":[null,{"b":[1],"c":[2]}]}', but
SELECT jsonb_insert('{"a":[null,{"b":[1]}]}', '{a,1,b}', jsonb '[2]')
-- will raise SQLSTATE 22023 (invalid_parameter_value): cannot replace existing key

JSON ऑब्जेक्ट से एक कुंजी (या एक इंडेक्स) हटाना (या, एक सरणी से) -ऑपरेटर के साथ किया जा सकता है :

SELECT jsonb '{"a":1,"b":2}' - 'a', -- will yield jsonb '{"b":2}'
       jsonb '["a",1,"b",2]' - 1    -- will yield jsonb '["a","b",2]'

JSON पदानुक्रम में गहरे से हटाकर,#- ऑपरेटर के साथ किया जा सकता है :

SELECT '{"a":[null,{"b":[3.14]}]}' #- '{a,1,b,0}'
-- will yield jsonb '{"a":[null,{"b":[]}]}'

9.4 के लिए , आप मूल उत्तर (नीचे) के संशोधित संस्करण का उपयोग कर सकते हैं, लेकिन JSON स्ट्रिंग को एग्रीगेट करने के बजाय, आप सीधे किसी json ऑब्जेक्ट में एग्रीगेट कर सकते हैं json_object_agg()

मूल उत्तर : शुद्ध एसक्यूएल में भी यह (प्लिफ़थॉन या plv8 के बिना) संभव है (लेकिन 9.3+ की ज़रूरत है, पहले नहीं होगा)

CREATE OR REPLACE FUNCTION "json_object_set_key"(
  "json"          json,
  "key_to_set"    TEXT,
  "value_to_set"  anyelement
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT concat('{', string_agg(to_json("key") || ':' || "value", ','), '}')::json
  FROM (SELECT *
          FROM json_each("json")
         WHERE "key" <> "key_to_set"
         UNION ALL
        SELECT "key_to_set", to_json("value_to_set")) AS "fields"
$function$;

SQLFiddle

संपादित करें :

एक संस्करण, जो कई कुंजी और मान सेट करता है:

CREATE OR REPLACE FUNCTION "json_object_set_keys"(
  "json"          json,
  "keys_to_set"   TEXT[],
  "values_to_set" anyarray
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT concat('{', string_agg(to_json("key") || ':' || "value", ','), '}')::json
  FROM (SELECT *
          FROM json_each("json")
         WHERE "key" <> ALL ("keys_to_set")
         UNION ALL
        SELECT DISTINCT ON ("keys_to_set"["index"])
               "keys_to_set"["index"],
               CASE
                 WHEN "values_to_set"["index"] IS NULL THEN 'null'::json
                 ELSE to_json("values_to_set"["index"])
               END
          FROM generate_subscripts("keys_to_set", 1) AS "keys"("index")
          JOIN generate_subscripts("values_to_set", 1) AS "values"("index")
         USING ("index")) AS "fields"
$function$;

संपादित करें 2 : जैसा कि @ErwinBrandstetter ने उपरोक्त कार्यों को एक तथाकथित की तरह काम किया है UPSERT(यदि यह मौजूद है तो फ़ील्ड को अपडेट करता है, अगर यह मौजूद नहीं है तो सम्मिलित करता है)। यहाँ एक संस्करण है, जो केवल UPDATE:

CREATE OR REPLACE FUNCTION "json_object_update_key"(
  "json"          json,
  "key_to_set"    TEXT,
  "value_to_set"  anyelement
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT CASE
  WHEN ("json" -> "key_to_set") IS NULL THEN "json"
  ELSE (SELECT concat('{', string_agg(to_json("key") || ':' || "value", ','), '}')
          FROM (SELECT *
                  FROM json_each("json")
                 WHERE "key" <> "key_to_set"
                 UNION ALL
                SELECT "key_to_set", to_json("value_to_set")) AS "fields")::json
END
$function$;

संपादित करें 3 : यहाँ पुनरावर्ती संस्करण है, जो UPSERTएक कुंजी-पथ पर स्थित एक पत्ती मान (और इस उत्तर से पहले फ़ंक्शन का उपयोग करता है) सेट कर सकता है (जहां कुंजियाँ केवल आंतरिक वस्तुओं का उल्लेख कर सकती हैं, आंतरिक सरणियाँ समर्थित नहीं हैं):

CREATE OR REPLACE FUNCTION "json_object_set_path"(
  "json"          json,
  "key_path"      TEXT[],
  "value_to_set"  anyelement
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT CASE COALESCE(array_length("key_path", 1), 0)
         WHEN 0 THEN to_json("value_to_set")
         WHEN 1 THEN "json_object_set_key"("json", "key_path"[l], "value_to_set")
         ELSE "json_object_set_key"(
           "json",
           "key_path"[l],
           "json_object_set_path"(
             COALESCE(NULLIF(("json" -> "key_path"[l])::text, 'null'), '{}')::json,
             "key_path"[l+1:u],
             "value_to_set"
           )
         )
       END
  FROM array_lower("key_path", 1) l,
       array_upper("key_path", 1) u
$function$;

अद्यतन : फ़ंक्शंस को अब कॉम्पैक्ट किया जाता है।


5
मैंने आपके plpgsql फ़ंक्शन की कोशिश की, लेकिन यह सुनिश्चित नहीं है कि इसका उपयोग कैसे किया जाए - जब मैं select json_object_set_key((select data from test where data->>'b' = '2'), 'b', 'two'); त्रुटि संदेश ERROR: could not determine polymorphic type because input has type "unknown"
आज़माता

1
यह ए के बराबर प्रदर्शन करता है, ए UPSERTनहीं UPDATE। यदि कुंजी अभी तक json फ़ील्ड में मौजूद नहीं है, तो इसे जोड़ा जाता है। एक वास्तविक के लिए इस संबंधित प्रश्न को देखें UPDATE: stackoverflow.com/questions/7711432/… (यह एक समग्र प्रकार के लिए है, लेकिन प्रिंसिपल json के लिए समान है।)
एरविन ब्रांडस्टेटर

1
@ErwinBrandstetter जो सच है, लेकिन json में एक UPSERT आमतौर पर एक UPDATE जैसे संशोधन ( f.ex. sqlfiddle.com/# -15/d41d8/2897 पर विचार करें ) की तुलना में अधिक सामान्य है - आप कैसे संशोधित करते हैं मूल प्रश्न की व्याख्या की है; UPDATE स्टेटमेंट का उपयोग करके उन्हें (json कॉलम)? - एक शर्त के अलावा यह UPDATE में बदल सकता है।
pozs

1
बहुत उपयोगी और अब पूरा।
इरविन ब्रान्डस्टेट्टर

1
@ maxhud जो क्लाइंट (या आपके द्वारा उपयोग किए जाने वाले क्लाइंट लाइब्रेरी) पर निर्भर करता है। यदि आप कर सकते हैं, तो स्पष्ट प्रकारों का उपयोग करें (PostgreSQL पैराट्राइज्ड प्रश्नों में प्रकारों का अनुमान लगा सकता है, लेकिन यह आमतौर पर बहुरूपी कार्यों के साथ अच्छी तरह से काम नहीं करता है)। लेकिन कम से कम, आप स्पष्ट जाति का उपयोग कर सकते हैं, जैसे $2::text
pozs

98

9.5 के साथ jsonb_set का उपयोग करें-

UPDATE objects
SET body = jsonb_set(body, '{name}', '"Mary"', true)
WHERE id = 1; 

जहाँ शरीर एक jsonb कॉलम प्रकार है।


नमस्ते, मैं इस upperतरह का उपयोग क्यों नहीं कर सकता : update objects set body=jsonb_set(body, '{name}', upper('"Mary"'), true) where id=1;यह पहचान नहीं करता है, या मैं समान व्यवहार कैसे प्राप्त कर सकता हूं? thx
राफेल कैपुचो

1
यदि मैं जो मूल्य निर्धारित करना चाहता हूं, वह "मैरी" के बजाय किसी अन्य कॉलम का एक विकल्प है, तो मैं यह कैसे करूंगा?
एंड्रयू

58

Postgresql 9.5 के साथ यह निम्नलिखित द्वारा किया जा सकता है-

UPDATE test
SET data = data - 'a' || '{"a":5}'
WHERE data->>'b' = '2';

या

UPDATE test
SET data = jsonb_set(data, '{a}', '5'::jsonb);

किसी ने पूछा कि एक ही बार में कई फील्ड्स को jsonb वैल्यू में कैसे अपडेट करें। मान लें कि हम एक तालिका बनाते हैं:

CREATE TABLE testjsonb ( id SERIAL PRIMARY KEY, object JSONB );

फिर हम एक प्रयोगात्मक पंक्ति सम्मिलित करते हैं:

INSERT INTO testjsonb
VALUES (DEFAULT, '{"a":"one", "b":"two", "c":{"c1":"see1","c2":"see2","c3":"see3"}}');

फिर हम पंक्ति को अद्यतन करते हैं:

UPDATE testjsonb SET object = object - 'b' || '{"a":1,"d":4}';

जो निम्न कार्य करता है:

  1. किसी क्षेत्र को अद्यतन करता है
  2. बी क्षेत्र निकालता है
  3. डी फ़ील्ड जोड़ें

डेटा का चयन:

SELECT jsonb_pretty(object) FROM testjsonb;

में परिणाम होगा:

      jsonb_pretty
-------------------------
 {                      +
     "a": 1,            +
     "c": {             +
         "c1": "see1",  +
         "c2": "see2",  +
         "c3": "see3",  +
     },                 +
     "d": 4             +
 }
(1 row)

फ़ील्ड को अपडेट करने के लिए, न तो कॉनैट ऑपरेटर का उपयोग करें ||। इसके बजाय jsonb_set का उपयोग करें। जो सरल नहीं है:

UPDATE testjsonb SET object =
jsonb_set(jsonb_set(object, '{c,c1}','"seeme"'),'{c,c2}','"seehim"');

उदाहरण के लिए, {c, c1} के लिए कॉनैट ऑपरेटर का उपयोग करना:

UPDATE testjsonb SET object = object || '{"c":{"c1":"seedoctor"}}';

{C, c2} और {c, c3} को हटा देगा।

अधिक शक्ति के लिए, postgresql json फ़ंक्शन प्रलेखन में शक्ति की तलाश करें#-ऑपरेटर, jsonb_setफ़ंक्शन और jsonb_insertफ़ंक्शन में भी रुचि हो सकती है ।


और अगर मुझे दो फ़ील्ड अपडेट करने हैं तो सिंटैक्स क्या है?
सुनील गर्ग

अगर मेरे पास फ़ील्ड नाम के साथ एक json कॉलम है, तो मैं इस कॉलम में lastname फ़ील्ड कैसे
जोड़ूँ

स्पष्ट होना चाहिए:UPDATE users SET profile = profile || '{"lastname":"Washington"}' WHERE profile->>'name' = 'George Washington';
फांदी सुसंतो

9

@ Pozs के उत्तरों के निर्माण के लिए, यहां कुछ और पोस्टग्रेक्सेल फ़ंक्शन हैं जो कुछ के लिए उपयोगी हो सकते हैं। (PostgreSQL 9.3+ की आवश्यकता है)

कुंजी द्वारा हटाएं: JSON संरचना से कुंजी द्वारा मान हटाता है।

CREATE OR REPLACE FUNCTION "json_object_del_key"(
  "json"          json,
  "key_to_del"    TEXT
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT CASE
  WHEN ("json" -> "key_to_del") IS NULL THEN "json"
  ELSE (SELECT concat('{', string_agg(to_json("key") || ':' || "value", ','), '}')
          FROM (SELECT *
                  FROM json_each("json")
                 WHERE "key" <> "key_to_del"
               ) AS "fields")::json
END
$function$;

कुंजी द्वारा पुनरावर्ती हटाएँ: कुंजी-पथ द्वारा JSON संरचना से एक मान हटाता है। (@ pozs json_object_set_keyफ़ंक्शन की आवश्यकता है )

CREATE OR REPLACE FUNCTION "json_object_del_path"(
  "json"          json,
  "key_path"      TEXT[]
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT CASE
  WHEN ("json" -> "key_path"[l] ) IS NULL THEN "json"
  ELSE
     CASE COALESCE(array_length("key_path", 1), 0)
         WHEN 0 THEN "json"
         WHEN 1 THEN "json_object_del_key"("json", "key_path"[l])
         ELSE "json_object_set_key"(
           "json",
           "key_path"[l],
           "json_object_del_path"(
             COALESCE(NULLIF(("json" -> "key_path"[l])::text, 'null'), '{}')::json,
             "key_path"[l+1:u]
           )
         )
       END
    END
  FROM array_lower("key_path", 1) l,
       array_upper("key_path", 1) u
$function$;

उपयोग के उदाहरण:

s1=# SELECT json_object_del_key ('{"hello":[7,3,1],"foo":{"mofu":"fuwa", "moe":"kyun"}}',
                                 'foo'),
            json_object_del_path('{"hello":[7,3,1],"foo":{"mofu":"fuwa", "moe":"kyun"}}',
                                 '{"foo","moe"}');

 json_object_del_key |          json_object_del_path
---------------------+-----------------------------------------
 {"hello":[7,3,1]}   | {"hello":[7,3,1],"foo":{"mofu":"fuwa"}}

बहुत उपयोगी! धन्यवाद।
1111161171159459134

9
UPDATE test
SET data = data::jsonb - 'a' || '{"a":5}'::jsonb
WHERE data->>'b' = '2'

ऐसा लगता है कि PostgreSQL 9.5 पर काम कर रहा है


मेरे लिए काम करता है, जहां तक ​​मैंने समझा है, यह डेटा से फ़ील्ड "ए" को हटा देता है और फिर नए मूल्य के साथ फ़ील्ड "ए" को जोड़ देता है। मेरे मामले में, "a" का मान एक कॉलम पर आधारित था। अद्यतन परीक्षण सेट डेटा = डेटा :: jsonb - 'ए' || ('{"a": "' || myColumn || '"}') :: jsonb?
sebge2

7

यदि आपका फ़ील्ड प्रकार json का है, तो निम्न आपके लिए काम करेंगे।

UPDATE 
table_name
SET field_name = field_name::jsonb - 'key' || '{"key":new_val}' 
WHERE field_name->>'key' = 'old_value'.

ऑपरेटर '-' बाएं ऑपरेटर से कुंजी / मान जोड़ी या स्ट्रिंग तत्व हटाएं। कुंजी / मूल्य जोड़े उनके प्रमुख मूल्य के आधार पर मेल खाते हैं।

संचालक '||' एक नए jsonb मान में दो jsonb मानों को मिलाएं।

चूंकि ये jsonb ऑपरेटर हैं, इसलिए आपको बस :: jsonb टाइपकास्ट करना होगा

अधिक जानकारी: JSON फ़ंक्शंस और ऑपरेटर्स

आप मेरा नोट यहाँ पढ़ सकते हैं


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

4

PostgreSQL 9.4 के साथ, हमने निम्नलिखित अजगर फ़ंक्शन को लागू किया है। यह PostgreSQL 9.3 के साथ भी काम कर सकता है।

create language plpython2u;

create or replace function json_set(jdata jsonb, jpaths jsonb, jvalue jsonb) returns jsonb as $$
import json

a = json.loads(jdata)
b = json.loads(jpaths)

if a.__class__.__name__ != 'dict' and a.__class__.__name__ != 'list':
  raise plpy.Error("The json data must be an object or a string.")

if b.__class__.__name__ != 'list':
   raise plpy.Error("The json path must be an array of paths to traverse.")

c = a
for i in range(0, len(b)):
  p = b[i]
  plpy.notice('p == ' + str(p))

  if i == len(b) - 1:
    c[p] = json.loads(jvalue)

  else:
    if p.__class__.__name__ == 'unicode':
      plpy.notice("Traversing '" + p + "'")
      if c.__class__.__name__ != 'dict':
        raise plpy.Error("  The value here is not a dictionary.")
      else:
        c = c[p]

    if p.__class__.__name__ == 'int':
      plpy.notice("Traversing " + str(p))
      if c.__class__.__name__ != 'list':
        raise plpy.Error("  The value here is not a list.")
      else:
        c = c[p]

    if c is None:
      break    

return json.dumps(a)
$$ language plpython2u ;

उदाहरण का उपयोग:

create table jsonb_table (jsonb_column jsonb);
insert into jsonb_table values
('{"cars":["Jaguar", {"type":"Unknown","partsList":[12, 34, 56]}, "Atom"]}');

select jsonb_column->'cars'->1->'partsList'->2, jsonb_column from jsonb_table;

update jsonb_table
set jsonb_column = json_set(jsonb_column, '["cars",1,"partsList",2]', '99');

select jsonb_column->'cars'->1->'partsList'->2, jsonb_column from jsonb_table;

ध्यान दें कि एक पिछले नियोक्ता के लिए, मैं पाठ के रूप में JSON डेटा जोड़ तोड़ (एक के रूप में नहीं के लिए सी कार्यों का एक सेट लिखा है jsonया jsonbPostgreSQL 7, 8 और 9 के लिए उदाहरण के लिए प्रकार), के साथ डेटा निकालने json_path('{"obj":[12, 34, {"num":-45.67}]}', '$.obj[2]['num']')डेटा के साथ, की स्थापना json_path_set('{"obj":[12, 34, {"num":-45.67}]}', '$.obj[2]['num']', '99.87')और इतने पर। इसमें लगभग 3 दिन का समय लगता है, इसलिए यदि आपको विरासत प्रणालियों पर चलने की आवश्यकता है और अतिरिक्त समय है, तो यह प्रयास के लायक हो सकता है। मुझे लगता है कि सी संस्करण अजगर संस्करण की तुलना में बहुत तेज है।


2

भले ही निम्नलिखित इस अनुरोध को पूरा नहीं करेगा (PostgreSQL 9.3 में फ़ंक्शन json_object_agg उपलब्ध नहीं है), निम्नलिखित किसी के लिए भी उपयोगी हो सकता है। PostgreSQL 9.4 के लिए ऑपरेटर, जैसा कि आगामी PostgreSQL 9.5 में लागू किया गया है:

CREATE OR REPLACE FUNCTION jsonb_merge(left JSONB, right JSONB)
RETURNS JSONB
AS $$
SELECT
  CASE WHEN jsonb_typeof($1) = 'object' AND jsonb_typeof($2) = 'object' THEN
       (SELECT json_object_agg(COALESCE(o.key, n.key), CASE WHEN n.key IS NOT NULL THEN n.value ELSE o.value END)::jsonb
        FROM jsonb_each($1) o
        FULL JOIN jsonb_each($2) n ON (n.key = o.key))
   ELSE 
     (CASE WHEN jsonb_typeof($1) = 'array' THEN LEFT($1::text, -1) ELSE '['||$1::text END ||', '||
      CASE WHEN jsonb_typeof($2) = 'array' THEN RIGHT($2::text, -1) ELSE $2::text||']' END)::jsonb
   END     
$$ LANGUAGE sql IMMUTABLE STRICT;
GRANT EXECUTE ON FUNCTION jsonb_merge(jsonb, jsonb) TO public;
CREATE OPERATOR || ( LEFTARG = jsonb, RIGHTARG = jsonb, PROCEDURE = jsonb_merge );

2

मैंने अपने लिए एक छोटा सा फंक्शन लिखा है जो पोस्टग्रैजेस 9.4 में रिकर्सिवली काम करता है। यहाँ फ़ंक्शन है (मुझे आशा है कि यह आपके लिए अच्छा काम करेगा):

CREATE OR REPLACE FUNCTION jsonb_update(val1 JSONB,val2 JSONB)
RETURNS JSONB AS $$
DECLARE
    result JSONB;
    v RECORD;
BEGIN
    IF jsonb_typeof(val2) = 'null'
    THEN 
        RETURN val1;
    END IF;

    result = val1;

    FOR v IN SELECT key, value FROM jsonb_each(val2) LOOP

        IF jsonb_typeof(val2->v.key) = 'object'
            THEN
                result = result || jsonb_build_object(v.key, jsonb_update(val1->v.key, val2->v.key));
            ELSE
                result = result || jsonb_build_object(v.key, v.value);
        END IF;
    END LOOP;

    RETURN result;
END;
$$ LANGUAGE plpgsql;

यहाँ नमूना उपयोग है:

select jsonb_update('{"a":{"b":{"c":{"d":5,"dd":6},"cc":1}},"aaa":5}'::jsonb, '{"a":{"b":{"c":{"d":15}}},"aa":9}'::jsonb);
                            jsonb_update                             
---------------------------------------------------------------------
 {"a": {"b": {"c": {"d": 15, "dd": 6}, "cc": 1}}, "aa": 9, "aaa": 5}
(1 row)

जैसा कि आप देख सकते हैं कि यह गहराई से विश्लेषण करता है और जहां आवश्यक है वहां मान जोड़ें / अपडेट करें।


2

यह मेरे लिए काम किया, जब एक स्ट्रिंग प्रकार के क्षेत्र को अपडेट करने की कोशिश की।

UPDATE table_name 
SET body = jsonb_set(body, '{some_key}', to_json('value'::TEXT)::jsonb);

आशा है कि यह किसी और की मदद करता है!

मान लें कि table_name में एक jsonb कॉलम है जिसका नाम बॉडी है और आप बॉडी बदलना चाहते हैं। some_key = 'value'


दुर्भाग्य से यह सुधार JSON के JSON- विशिष्ट कार्यों के माध्यम से छेड़छाड़ के समान है
Lu55

1

अफसोस की बात यह है कि मैंने प्रलेखन में कुछ भी नहीं पाया है, लेकिन आप कुछ वर्कअराउंड का उपयोग कर सकते हैं, उदाहरण के लिए आप कुछ विस्तारित फ़ंक्शन लिख सकते हैं।

उदाहरण के लिए, पायथन में:

CREATE or REPLACE FUNCTION json_update(data json, key text, value json)
returns json
as $$
from json import loads, dumps
if key is None: return data
js = loads(data)
js[key] = value
return dumps(js)
$$ language plpython3u

और फिर

update test set data=json_update(data, 'a', to_json(5)) where data->>'b' = '2';

यह शर्म की बात है अमेज़न RDS plpython3u का समर्थन नहीं करता है!
dbau

2
valueयह भी एक की आवश्यकता होगी loadsजब तार (जैसे गैर संख्यात्मक मान की स्थापना js[key] = loads(value):) - नहीं तोselect json_update('{"a":"a"}', 'a', to_json('b')); -> {"a": "\"b\""}
hooblei

इस उत्तर को तब भी संशोधित किया जा सकता है, जब मूल्य को कोई भी सेट करने के लिए कुंजी को हटाना शामिल है: `यदि मूल्य कोई नहीं है: डेल डेटा [कुंजी]
जोशुआ बर्न्स

1

निम्नलिखित प्लिफथॉन स्निपेट काम में आ सकता है।

CREATE EXTENSION IF NOT EXISTS plpythonu;
CREATE LANGUAGE plpythonu;

CREATE OR REPLACE FUNCTION json_update(data json, key text, value text)
 RETURNS json
 AS $$
    import json
    json_data = json.loads(data)
    json_data[key] = value
    return json.dumps(json_data, indent=4)
 $$ LANGUAGE plpythonu;

-- Check how JSON looks before updating

SELECT json_update(content::json, 'CFRDiagnosis.mod_nbs', '1')
FROM sc_server_centre_document WHERE record_id = 35 AND template = 'CFRDiagnosis';

-- Once satisfied update JSON inplace

UPDATE sc_server_centre_document SET content = json_update(content::json, 'CFRDiagnosis.mod_nbs', '1')
WHERE record_id = 35 AND template = 'CFRDiagnosis';

1

मैंने पाया कि पिछले उत्तर उपयुक्त अनुभवी PostgreSQL उपयोगकर्ता हैं, इसलिए मेरा उत्तर है:

मान लें कि आपके पास निम्न मान के साथ JSONB का एक तालिका-स्तंभ है:

{
    "key0": {
        "key01": "2018-05-06T12:36:11.916761+00:00",
        "key02": "DEFAULT_WEB_CONFIGURATION",

    "key1": {
        "key11": "Data System",
        "key12": "<p>Health,<p>my address<p>USA",
        "key13": "*Please refer to main screen labeling"
    }
}

मान लें कि हम पंक्ति में एक नया मान सेट करना चाहते हैं:

"key13": "*Please refer to main screen labeling"

और इसके बजाय मान रखें:

"key13": "See main screen labeling"

हम कुंजी 13 को नया मान असाइन करने के लिए json_set () फ़ंक्शन का उपयोग करते हैं

jsonb_set () के पैरामीटर

jsonb_set(target jsonb, path text[], new_value jsonb[, create_missing boolean])

" लक्ष्य " में - मैं jsonb कॉलम-नाम रखूँगा (यह टेबल कॉलम है जिसे संशोधित किया जा रहा है)

" पाथ " - "जोंस कीज़ पाथ" प्रमुख-से (और इसमें शामिल) वह कुंजी है जिसे हम अधिलेखित करने जा रहे हैं

" new_value " - यह नया मूल्य है जिसे हम असाइन करते हैं

हमारे मामले में हम key13 के मान को अद्यतन करना चाहते हैं जो कि की 1 के अंतर्गत रहता है (की1 -> की 13):

इसलिए पथ सिंटैक्स है: '{key1, key13}' (पथ क्रैक करने के लिए सबसे मुश्किल हिस्सा था - क्योंकि ट्यूटोरियल भयानक है)

jsonb_set(jsonb_column,'{key1,key13}','"See main screen labeling"')

0

आप jsonbइस तरह से भी परमाणु कुंजी को बढ़ा सकते हैं :

UPDATE users SET counters = counters || CONCAT('{"bar":', COALESCE(counters->>'bar','0')::int + 1, '}')::jsonb WHERE id = 1;

SELECT * FROM users;

 id |    counters
----+------------
  1 | {"bar": 1}

अपरिभाषित कुंजी -> मान 0 के शुरुआती मूल्य।

अधिक विस्तृत विवरण के लिए, मेरा जवाब यहां देखें: https://stackoverflow.com/a/39076637


0

उपयोग करने वालों के लिए mybatis, यहां एक उदाहरण अपडेट स्टेटमेंट है:

<update id="saveAnswer">
    update quiz_execution set answer_data = jsonb_set(answer_data, concat('{', #{qid}, '}')::text[], #{value}::jsonb), updated_at = #{updatedAt}
    where id = #{id}
</update>


पैरामीटर:

  • qidक्षेत्र के लिए महत्वपूर्ण है।
  • value, फील्ड वैल्यू के लिए एक वैध जौन स्ट्रिंग है,
    उदाहरण के लिए ऑब्जेक्ट से जौन स्ट्रिंग में परिवर्तित किया जाता है jackson,

0

इसलिए, उदाहरण के लिए मेरा तार इस तरह दिखता है: {"a1": {"a11": "x", "a22": "y", "a33": "z"}}

मैं टेम्पों टेबल का उपयोग करके jsons को अपडेट करता हूं, जो डेटा के बजाय छोटे गोलाकार के लिए काफी अच्छा है (<1.000.000)। मुझे एक अलग रास्ता मिल गया, लेकिन फिर छुट्टी पर चला गया और इसे भूल गया ...

इसलिए। क्वेरी कुछ इस तरह होगी:

with temp_table as (
select 
a.id,
a->'a1'->>'a11' as 'a11',
a->'a1'->>'a22' as 'a22',
a->'a1'->>'a33' as 'a33',
u1.a11updated
from foo a
join table_with_updates u1 on u1.id = a.id)
    update foo a
    set a = ('{"a1": {"a11": "'|| t.a11updated ||'",
        "a22":"'|| t.a22 ||'",
        "a33":"'|| t.a33 ||'"}}')::jsonb
    from temp_table t
    where t.id = a.id;

यह json की तुलना में स्ट्रिंग के साथ अधिक है, लेकिन यह काम करता है। मूल रूप से, यह सभी डेटा को अस्थायी तालिका में खींचता है, आपके द्वारा समर्थित डेटा के साथ कॉनटैट छेद को प्लग करते समय एक स्ट्रिंग बनाता है, और इसे जोंसब में परिवर्तित करता है।

Json_set अधिक कुशल हो सकता है, लेकिन मैं अभी भी इसे लटका रहा हूं। पहली बार मैंने इसका उपयोग करने की कोशिश की, मैंने स्ट्रिंग को पूरी तरह से गड़बड़ कर दिया ...


1
नमस्ते और StackOverflow में आपका स्वागत है! ध्यान दें कि इस प्रश्न का पहले से ही स्वीकृत उत्तर है।
hongsy

-2

यदि आप इस क्वेरी को प्रोग्रामिंग लैंग्वेज क्लाइंट के साथ बना रहे हैं, जैसे कि python pycopg2, या Node Postgres, सुनिश्चित करें कि आप पहले JSON के नए डेटा को पार्स करते हैं।

यह आसानी से एक अजगर की तरह लग सकता है शब्दकोश एक JSON वस्तु के रूप में ही है, लेकिन यह पहले शब्दकोश पर json.dumps नहीं करता है।

एक साधारण अजगर स्निपेट:

def change_destination(self,parcel_id,destlatlng): query="UPDATE parcels SET destlatlng = '{}' WHERE parcel_id ={};".format(json.dumps(destlatlng), parcel_id) self.cursor.execute(query2) self.connection.commit()

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.