Yeni PostgreSQL JSON veri türü içindeki alanları nasıl değiştirebilirim?


235

Postgresql 9.3 ile bir JSON veri türünün belirli alanlarını SEÇEBİLİRİM, ancak UPDATE kullanarak bunları nasıl değiştirirsiniz? Bunun herhangi bir örneğini postgresql belgelerinde veya çevrimiçi herhangi bir yerde bulamıyorum. Ben bariz denedim:

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...

Yanıtlar:


331

Güncelleme : PostgreSQL 9.5 ile , jsonbPostgreSQL'in içinde bazı manipülasyon işlevleri vardır (ancak değerlerin jsonmanipüle edilmesi için dökümler gerekmez json).

2 (veya daha fazla) JSON nesnesini (veya sıralı dizileri) birleştirme:

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]'

Böylece, basit bir anahtar ayarlamak aşağıdakileri kullanarak yapılabilir:

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

Nerede <key>dize olmalı ve <value>tür ne olursa olsun to_jsonb()kabul edilebilir.

İçin bir JSON hiyerarşisinde bir değer derine ayarlayarak , jsonb_set()fonksiyon kullanılabilir:

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

Aşağıdakilerin tam parametre listesi jsonb_set():

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

pathJSON dizi dizinleri de içerebilir ve orada görünen negatif tamsayılar JSON dizilerinin sonundan itibaren sayılabilir. Ancak, var olmayan ancak pozitif bir JSON dizi dizini, öğeyi dizinin sonuna ekler:

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

İçin (orijinal tüm değerleri korunurken) JSON diziye sokulması , jsonb_insert()fonksiyon kullanılabilir ( 9.6+ olarak, bu fonksiyon, sadece bu bölümde ):

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]}]}'

Aşağıdakilerin tam parametre listesi jsonb_insert():

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

Yine, pathJSON dizilerinin sonundan itibaren sayılan negatif tamsayılar .

Yani, f.ex. bir JSON dizisinin sonuna ekleme aşağıdakilerle yapılabilir:

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

Bununla birlikte, bu fonksiyon biraz farklı (daha çalışmaktadır jsonb_set()) zaman pathiçinde targetbir JSON nesnenin anahtarıdır. Bu durumda, yalnızca anahtar kullanılmadığında yalnızca JSON nesnesi için yeni bir anahtar / değer çifti ekleyecektir. Kullanılırsa bir hata oluşturur:

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 nesnesinden (veya bir diziden) bir anahtarı (veya dizini) silmek- operatörle yapılabilir :

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 hiyerarşisinin derinliklerinden silme#- operatörle yapılabilir :

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

9.4 için , orijinal yanıtın değiştirilmiş bir sürümünü kullanabilirsiniz (aşağıda), ancak bir JSON dizesini toplamak yerine, doğrudan bir json nesnesine toplayabilirsiniz json_object_agg().

Orijinal cevap : Saf SQL'de de (plpython veya plv8 olmadan) mümkündür (ancak 9.3+'ye ihtiyaç duyar, 9.2 ile çalışmaz)

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

Düzenle :

Birden çok anahtar ve değer ayarlayan bir sürüm:

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$;

Düzenleme 2 : @ErwinBrandstetter'in belirttiği gibi yukarıdaki bu işlevler sözde gibi çalışır UPSERT(varsa bir alanı günceller, yoksa ekler). İşte sadece bir varyant 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$;

Düzenleme 3 : Burada, UPSERTbir anahtar yolunda bulunan (anahtarların yalnızca iç nesnelere başvurabildiği, iç dizileri desteklenmediği) bir yaprak değeri ayarlayabilen ( ve bu yanıttan ilk işlevi kullanan) özyinelemeli varyant :

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$;

Güncelleme : fonksiyonlar şimdi sıkıştırılmıştır.


5
Plpgsql işlevinizi denedim, ancak nasıl kullanılacağından emin değilim - select json_object_set_key((select data from test where data->>'b' = '2'), 'b', 'two'); Hata mesajını denediğimde bir hata görüyorumERROR: could not determine polymorphic type because input has type "unknown"
user9645

1
Bu UPSERT, bir değil , bir eşdeğerini gerçekleştirir UPDATE. Anahtar henüz json alanında yoksa eklenir. Bir gerçek için bu ilgili soruya bakın UPDATE: stackoverflow.com/questions/7711432/… (Bu bileşik bir tür içindir, ancak temel json için benzerdir.)
Erwin Brandstetter

1
@ErwinBrandstetter bu doğru, ancak json'da bir UPSERT genellikle GÜNCELLEME benzeri bir modifikasyondan daha genel ( f.ex. sqlfiddle.com/#!15/d41d8/2897 ) - Orijinal soruyu nasıl değiştirdiğinizi yorumladım (json sütunları) bir UPDATE deyimi kullanarak? - tek bir koşulun yanı sıra bunu GÜNCELLEME'ye dönüştürebilir.
Ağustos'ta pozlar

1
Şimdi çok kullanışlı ve eksiksiz.
Erwin Brandstetter

1
@maksudud istemciye (veya kullandığınız istemci kitaplığına) bağlıdır. Mümkünse, açık türleri kullanın (PostgreSQL, parametrelenmiş sorgulardaki türleri tahmin edebilir, ancak genellikle polimorfik işlevlerle iyi çalışmaz). Ama en azından, açık dökümler kullanabilirsiniz $2::text.
pozlar

98

9.5 ile jsonb_set- kullanın

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

burada gövde bir jsonb sütun türüdür.


Merhaba, neden böyle kullanamıyorum upper: update objects set body=jsonb_set(body, '{name}', upper('"Mary"'), true) where id=1;tanımıyor veya aynı davranışı nasıl elde edebilirim? thx
Rafael Capucho

1
Ayarlamak istediğim değer "Mary" yerine başka bir sütundan bir alt dize ise, bunu nasıl yaparım?
Andrew

58

Postgresql 9.5 ile aşağıdaki işlemler yapılabilir.

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

VEYA

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

Birisi jsonb değerindeki birçok alanı aynı anda nasıl güncelleyeceğini sordu. Bir tablo oluşturduğumuzu varsayalım:

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

Sonra deneysel bir satır ekleriz:

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

Sonra satırı GÜNCELLEME:

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

Aşağıdakileri yapar:

  1. Bir alanı günceller
  2. B alanını kaldırır
  3. D alanını ekleyin

Verilerin seçilmesi:

SELECT jsonb_pretty(object) FROM testjsonb;

Sonuçlanacak:

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

İçindeki alanı güncellemek için concat operatörünü kullanmayın ||. Bunun yerine jsonb_set kullanın. Hangisi basit değil:

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

Örneğin, {c, c1} için concat operatörünü kullanma:

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

{C, c2} ve {c, c3} öğelerini kaldıracak.

Daha fazla güç için, postgresql json fonksiyonları belgelerinde güç arayın . #-Operatör, jsonb_setfonksiyon ve fonksiyon ile ilgilenilebilir jsonb_insert.


ve eğer iki alanı güncellemem gerekirse sözdizimi nedir?
Sunil Garg

alan adına sahip bir json
sütunum varsa

Açık olmalı:UPDATE users SET profile = profile || '{"lastname":"Washington"}' WHERE profile->>'name' = 'George Washington';
Fandi Susanto

9

@ Pozs'un cevapları üzerine inşa etmek için, bazıları için yararlı olabilecek birkaç tane daha PostgreSQL işlevi var. (PostgreSQL 9.3+ gerekir)

Anahtarla Sil: JSON yapısındaki bir değeri anahtar ile siler.

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$;

Yinelenen Anahtarla Sil: JSON yapısından bir değeri anahtar yoluna göre siler. (@ pozs json_object_set_keyişlevini gerektirir )

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$;

Kullanım örnekleri:

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"}}

Çok kullanışlı! Teşekkür ederim.
1111161171159459134

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

Bu PostgreSQL 9.5 üzerinde çalışıyor gibi görünüyor


Benim için çalışıyor, anladığım kadarıyla, bu alan "a" veriyi kaldırmak ve daha sonra "a" alanına yeni değeri ile ekleyin. Benim durumumda, "a" değeri bir sütuna dayanıyordu. UPDATE test SET verileri = data :: jsonb - 'a' || ('{"a": "' || myColumn || '"}') :: jsonb;
sebge2

7

Alan türünüz json ise aşağıdakiler sizin için çalışır.

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

Operatör '-' anahtar / değer çiftini veya dize öğesini sol işlenenden siler. Anahtar / değer çiftleri, anahtar değerlerine göre eşleştirilir.

Operatör '||' iki jsonb değerini yeni bir jsonb değerine birleştirin.

Bunlar jsonb operatörleri olduğundan sadece şunu yazmanız gerekir :: jsonb

Daha fazla bilgi: JSON İşlevleri ve İşleçleri

Notumu buradan okuyabilirsiniz


Mülk siparişi yeniden düzenlemelerinden endişe etmiyorsanız, JSON alanlarını güncellemenin basit ve daha iyi bir yolu.
Karthik Sivaraj

4

PostgreSQL 9.4 ile aşağıdaki python işlevini uyguladık. PostgreSQL 9.3 ile de çalışabilir.

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 ;

Örnek kullanım:

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;

Bir önceki işveren için, ben (bir olarak metin olarak JSON verileri değiştirmek için C fonksiyonları bir dizi yazdım Not jsonveya jsonbÖrneğin PostgreSQL 7, 8 ve 9 için tip) ile veri ayıklama json_path('{"obj":[12, 34, {"num":-45.67}]}', '$.obj[2]['num']')ile veri, ayar json_path_set('{"obj":[12, 34, {"num":-45.67}]}', '$.obj[2]['num']', '99.87')vb. Yaklaşık 3 gün sürdü, bu yüzden eski sistemlerde çalıştırmak ve zaman ayırmak için ihtiyacınız varsa, çabaya değebilir. C versiyonunun python versiyonundan çok daha hızlı olduğunu düşünüyorum.


2

Aşağıdakiler bu isteği yerine getirmeyecek olsa da (json_object_agg işlevi PostgreSQL 9.3'te mevcut değildir), bir || yaklaşan PostgreSQL 9.5'te uygulandığı üzere PostgreSQL 9.4 için operatör:

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

Postgres 9.4'te kendiliğinden çalışan küçük bir işlev yazdım. İşte işlevi (umarım sizin için iyi çalışır):

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;

İşte örnek kullanım:

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)

Gördüğünüz gibi derinlemesine analiz edin ve gerektiğinde değerleri güncelleyin / ekleyin.


2

Bir dize türü alanını güncellemeye çalışırken bu benim için çalıştı.

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

Umarım başkasına yardım eder!

Table_name tablosunun body adında bir jsonb sütunu olduğunu ve body.some_key = 'value' değerini değiştirmek istediğinizi varsayarsak


maalesef bu
JSON'u, JSON'a

1

Ne yazık ki, belgelerde hiçbir şey bulamadım, ancak bazı geçici çözümler kullanabilirsiniz, örneğin bazı genişletilmiş işlevler yazabilirsiniz.

Örneğin, Python'da:

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

ve sonra

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

Amazon RDS'nin plpython3u'yu desteklememesi utanç verici!
dbau

2
Ayrıca value, loadsdizeler ( js[key] = loads(value)) gibi sayısal olmayan değerleri ayarlarken bir de gerekir. Aksi takdirde:select json_update('{"a":"a"}', 'a', to_json('b')); -> {"a": "\"b\""}
hooblei

Bu yanıt, değer Yok olarak ayarlandığında bir anahtarın silinmesini içerecek şekilde de değiştirilebilir: `değer Yok ise: del data [anahtar]
Joshua Burns

1

Aşağıdaki plpython snippet'i kullanışlı olabilir.

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

Önceki cevapların uygun deneyimli PostgreSQL kullanıcıları olduğunu gördüm, dolayısıyla cevabım:

Aşağıdaki değere sahip JSONB türünde bir tablo sütununa sahip olduğunuzu varsayın:

{
    "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"
    }
}

satırda yeni bir değer ayarlamak istediğimizi varsayalım:

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

ve bunun yerine değeri yerleştirin:

"key13": "See main screen labeling"

key13'e yeni bir değer atamak için json_set () işlevini kullanıyoruz

jsonb_set () için parametreler

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

" target " - jsonb sütun adını yerleştireceğim (bu değiştirilmekte olan tablo sütunudur)

" path " - üzerine yazacağımız anahtara giden (ve dahil) "json anahtarları yoludur"

" new_value " - atadığımız yeni değer

bizim durumumuzda, key1 (key1 -> key13) altında bulunan 13 anahtarının değerini güncellemek istiyoruz:

bu nedenle yol sözdizimi şöyledir: '{key1, key13}' (Yol kırmak için en zor kısımdı - öğreticiler korkunç olduğu için)

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

0

Anahtarları atomik olarak şu şekilde artırabilirsiniz 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}

Tanımsız anahtar -> başlangıç ​​değerini 0 olarak kabul eder.

Daha ayrıntılı açıklama için cevabımı buraya bakın: https://stackoverflow.com/a/39076637


0

Kullananlar mybatisiçin örnek bir güncelleme bildirimi:

<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>


parametreler:

  • qid, alan anahtarı.
  • value, alan değeri için geçerli bir json dizesidir,
    örneğin, nesneden json dizesine jackson,

0

Örneğin, dizem şöyle görünür: {"a1": {"a11": "x", "a22": "y", "a33": "z"}}

Jsons'ı, oldukça küçük miktarda veri (<1.000.000) için yeterince iyi olan geçici tabloyu kullanarak güncelliyorum. Farklı bir yol buldum, ama sonra tatile çıktım ve unuttum ...

Yani. sorgu şu şekilde olacaktır:

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;

String ile json'dan daha fazlası var, ama işe yarıyor. Temel olarak, tüm verileri geçici tabloya çeker, yedeklediğiniz verilerle bitişik delikler eklerken bir dize oluşturur ve jsonb'ye dönüştürür.

Json_set daha etkili olabilir, ama yine de asıyorum. İlk kez kullanmaya çalıştığımda, dizeyi tamamen berbat ettim ...


1
merhaba ve StackOverflow'a hoş geldiniz! Bu sorunun zaten kabul edilmiş bir cevabı olduğunu unutmayın.
hongsy

-2

Bu sorguyu bir programlama dili istemcisi ile yapıyorsanız, örneğin python pycopg2, veya Node Postgres, Önce yeni verileri JSON ile ayrıştırdığınızdan emin olun.

Kolayca bir python sözlüğü bir JSON nesnesiyle aynı gibi görünebilir, ancak ilk olarak sözlükte json.dumps yapmaz.

Basit bir python snippet'i:

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()

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.