Update : Mit PostgreSQL 9.5 gibt es einige jsonb
Manipulationsfunktionen in PostgreSQL selbst (aber keine für json
; Casts sind erforderlich, um json
Werte zu manipulieren ).
Zusammenführen von 2 (oder mehr) JSON-Objekten (oder Verketten von Arrays):
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]'
Das Einstellen eines einfachen Schlüssels kann also folgendermaßen erfolgen:
SELECT jsonb '{"a":1}' || jsonb_build_object('<key>', '<value>')
Wo <key>
sollte Zeichenfolge sein, und <value>
kann jeder Typ sein, der to_jsonb()
akzeptiert.
Zum Festlegen eines Werts tief in einer JSON-Hierarchie kann die folgende jsonb_set()
Funktion verwendet werden:
SELECT jsonb_set('{"a":[null,{"b":[]}]}', '{a,1,b,0}', jsonb '{"c":3}')
-- will yield jsonb '{"a":[null,{"b":[{"c":3}]}]}'
Vollständige Parameterliste von jsonb_set()
:
jsonb_set(target jsonb,
path text[],
new_value jsonb,
create_missing boolean default true)
path
kann auch JSON-Array-Indizes enthalten & negative Ganzzahlen, die dort erscheinen, zählen ab dem Ende von JSON-Arrays. Ein nicht vorhandener, aber positiver JSON-Array-Index hängt das Element jedoch an das Ende des Arrays an:
SELECT jsonb_set('{"a":[null,{"b":[1,2]}]}', '{a,1,b,1000}', jsonb '3', true)
-- will yield jsonb '{"a":[null,{"b":[1,2,3]}]}'
Zum Einfügen in ein JSON-Array (unter Beibehaltung aller ursprünglichen Werte) kann die jsonb_insert()
Funktion verwendet werden ( in 9.6+; nur diese Funktion in diesem Abschnitt ):
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]}]}'
Vollständige Parameterliste von jsonb_insert()
:
jsonb_insert(target jsonb,
path text[],
new_value jsonb,
insert_after boolean default false)
Wiederum zählen negative Ganzzahlen, die path
ab dem Ende der JSON-Arrays angezeigt werden.
Also, z. Das Anhängen an ein Ende eines JSON-Arrays kann erfolgen mit:
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
Diese Funktion funktioniert jedoch etwas anders (als jsonb_set()
), wenn das path
In target
der Schlüssel eines JSON-Objekts ist. In diesem Fall wird nur dann ein neues Schlüssel-Wert-Paar für das JSON-Objekt hinzugefügt, wenn der Schlüssel nicht verwendet wird. Wenn es verwendet wird, wird ein Fehler ausgegeben:
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
Das Löschen eines Schlüssels (oder eines Index) aus einem JSON-Objekt (oder aus einem Array) kann mit dem -
Operator erfolgen:
SELECT jsonb '{"a":1,"b":2}' - 'a', -- will yield jsonb '{"b":2}'
jsonb '["a",1,"b",2]' - 1 -- will yield jsonb '["a","b",2]'
Das Löschen aus einer JSON-Hierarchie heraus kann mit dem #-
Operator erfolgen:
SELECT '{"a":[null,{"b":[3.14]}]}' #- '{a,1,b,0}'
-- will yield jsonb '{"a":[null,{"b":[]}]}'
Für 9.4 können Sie eine geänderte Version der ursprünglichen Antwort (unten) verwenden. Anstatt jedoch eine JSON-Zeichenfolge zu aggregieren, können Sie direkt mit zu einem JSON-Objekt aggregieren json_object_agg()
.
Ursprüngliche Antwort : Es ist möglich (ohne plpython oder plv8) auch in reinem SQL (benötigt aber 9.3+, funktioniert nicht mit 9.2)
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
Bearbeiten :
Eine Version, die mehrere Schlüssel und Werte festlegt:
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$;
Bearbeiten 2 : Wie @ErwinBrandstetter feststellte, funktionieren diese Funktionen wie ein sogenanntes UPSERT
(aktualisiert ein Feld, falls vorhanden, fügt ein, wenn es nicht vorhanden ist). Hier ist eine Variante, die nur 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$;
Bearbeiten 3 : Hier ist eine rekursive Variante, die UPSERT
einen Blattwert setzen ( ) kann (und die erste Funktion aus dieser Antwort verwendet), die sich an einem Schlüsselpfad befindet (wobei Schlüssel nur auf innere Objekte verweisen können, innere Arrays nicht unterstützt werden):
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$;
Update : Funktionen sind jetzt komprimiert.
select json_object_set_key((select data from test where data->>'b' = '2'), 'b', 'two');
Fehlermeldung wird ein FehlerERROR: could not determine polymorphic type because input has type "unknown"
UPSERT
, nicht einemUPDATE
. Wenn der Schlüssel noch nicht im Feld json vorhanden ist, wird er hinzugefügt. Schauen Sie sich diese verwandte Frage für eine aktuelle anUPDATE
: stackoverflow.com/questions/7711432/… (Dies ist für einen zusammengesetzten Typ, aber das Prinzip ist für json ähnlich.)$2::text
.Verwenden Sie mit 9.5 jsonb_set-
Dabei ist body ein jsonb-Spaltentyp.
quelle
upper
:update objects set body=jsonb_set(body, '{name}', upper('"Mary"'), true) where id=1;
es erkennt nicht, oder wie kann ich das gleiche Verhalten erreichen? thxMit Postgresql 9.5 können Sie Folgendes tun:
ODER
Jemand fragte, wie viele Felder im jsonb-Wert gleichzeitig aktualisiert werden könnten. Angenommen, wir erstellen eine Tabelle:
Dann fügen wir eine experimentelle Zeile ein:
Dann aktualisieren wir die Zeile:
Welches macht das Folgende:
Daten auswählen:
Wird darin enden, dass:
Verwenden Sie zum Aktualisieren des Felds nicht den concat-Operator
||
. Verwenden Sie stattdessen jsonb_set. Welches ist nicht einfach:Verwenden Sie den concat-Operator für {c, c1} zum Beispiel:
Entfernt {c, c2} und {c, c3}.
Weitere Informationen finden Sie in der Dokumentation zu den Funktionen von postgresql json . Man könnte sich für den
#-
Bediener, diejsonb_set
Funktion und auch diejsonb_insert
Funktion interessieren .quelle
UPDATE users SET profile = profile || '{"lastname":"Washington"}' WHERE profile->>'name' = 'George Washington';
Um auf den Antworten von @ pozs aufzubauen, finden Sie hier einige weitere PostgreSQL-Funktionen, die für einige nützlich sein können. (Erfordert PostgreSQL 9.3+)
Nach Schlüssel löschen : Löscht einen Wert aus der JSON-Struktur nach Schlüssel.
Rekursives Löschen nach Schlüssel: Löscht einen Wert aus der JSON-Struktur nach Schlüsselpfad. (erfordert die
json_object_set_key
Funktion von @ pozs )Anwendungsbeispiele:
quelle
Dies scheint unter PostgreSQL 9.5 zu funktionieren
quelle
Wenn Ihr Feldtyp json ist, funktioniert Folgendes für Sie.
Operator '-' Schlüssel / Wert-Paar oder String-Element aus dem linken Operanden löschen. Schlüssel / Wert-Paare werden basierend auf ihrem Schlüsselwert abgeglichen.
Operator '||' Verketten Sie zwei Jsonb-Werte zu einem neuen Jsonb-Wert.
Da es sich um jsonb-Operatoren handelt, müssen Sie nur Folgendes in :: jsonb eingeben
Weitere Informationen: JSON-Funktionen und Operatoren
Sie können meine Notiz hier lesen
quelle
Mit PostgreSQL 9.4 haben wir die folgende Python-Funktion implementiert. Es kann auch mit PostgreSQL 9.3 funktionieren.
Anwendungsbeispiel:
Beachten Sie, dass ich für einen früheren Arbeitgeber eine Reihe von C-Funktionen zum Bearbeiten von JSON-Daten als Text (nicht als
json
oderjsonb
Typ) für PostgreSQL 7, 8 und 9 geschrieben habe. Beispiel: Extrahieren von Daten mitjson_path('{"obj":[12, 34, {"num":-45.67}]}', '$.obj[2]['num']')
, Festlegen von Daten mitjson_path_set('{"obj":[12, 34, {"num":-45.67}]}', '$.obj[2]['num']', '99.87')
usw. Die Arbeit dauerte ungefähr 3 Tage. Wenn Sie es also benötigen, um auf Legacy-Systemen ausgeführt zu werden und Zeit zu haben, ist es möglicherweise die Mühe wert. Ich stelle mir vor, die C-Version ist viel schneller als die Python-Version.quelle
Obwohl das Folgende diese Anforderung nicht erfüllt (die Funktion json_object_agg ist in PostgreSQL 9.3 nicht verfügbar), kann das Folgende für jeden nützlich sein, der nach einem || sucht Operator für PostgreSQL 9.4, wie im kommenden PostgreSQL 9.5 implementiert:
quelle
Ich habe eine kleine Funktion für mich geschrieben, die in Postgres 9.4 rekursiv funktioniert. Hier ist die Funktion (ich hoffe, es funktioniert gut für Sie):
Hier ist ein Beispiel für die Verwendung:
Wie Sie sehen können, analysieren Sie tief im Inneren und aktualisieren / fügen Sie Werte hinzu, wo dies erforderlich ist.
quelle
Dies funktionierte bei mir, als ich versuchte, ein Zeichenfolgentypfeld zu aktualisieren.
Hoffe es hilft jemand anderem!
Angenommen, die Tabelle table_name hat eine jsonb-Spalte mit dem Namen body und Sie möchten body.some_key = 'value' ändern.
quelle
Leider habe ich in der Dokumentation nichts gefunden, aber Sie können eine Problemumgehung verwenden, z. B. eine erweiterte Funktion schreiben.
Zum Beispiel in Python:
und dann
quelle
value
erfordert auch ein,loads
wenn nicht numerische Werte wie Strings (js[key] = loads(value)
) gesetzt werden - Andernfalls:select json_update('{"a":"a"}', 'a', to_json('b')); -> {"a": "\"b\""}
Das folgende plpython-Snippet kann nützlich sein.
quelle
Ich habe festgestellt, dass frühere Antworten für erfahrene PostgreSQL-Benutzer geeignet sind, daher meine Antwort:
Angenommen, Sie haben eine Tabellenspalte vom Typ JSONB mit dem folgenden Wert:
Nehmen wir an, wir möchten einen neuen Wert in der Zeile festlegen:
und platzieren Sie stattdessen den Wert:
Wir verwenden die Funktion json_set (), um dem Schlüssel13 einen neuen Wert zuzuweisen
die Parameter zu jsonb_set ()
in " target " - Ich werde den jsonb-Spaltennamen platzieren (dies ist die Tabellenspalte, die geändert wird).
" path " - ist der "json keys path", der zu dem Schlüssel führt (und ihn einschließt), den wir überschreiben werden
" new_value " - Dies ist der neue Wert, den wir zuweisen
In unserem Fall möchten wir den Wert von key13 aktualisieren, der sich unter key1 befindet (key1 -> key13):
daher auch die Pfadsyntax ist: ‚{key1, key13}‘ (Der Weg war der schwierige Teil zu knacken - weil die Tutorials sind schrecklich)
quelle
Sie können Schlüssel auch atomar
jsonb
wie folgt inkrementieren :Undefinierter Schlüssel -> nimmt den Startwert 0 an.
Eine ausführlichere Erklärung finden Sie in meiner Antwort hier: https://stackoverflow.com/a/39076637
quelle
Für diejenigen, die verwenden
mybatis
, ist hier ein Beispiel für eine Update-Anweisung:Parameter:
qid
, der Schlüssel für Feld.value
ist eine gültige JSON-Zeichenfolge für den Feldwert,z. B. konvertiert von Objekt zu JSON-Zeichenfolge über
jackson
,quelle
So sieht meine Zeichenfolge beispielsweise folgendermaßen aus: {"a1": {"a11": "x", "a22": "y", "a33": "z"}}
Ich aktualisiere jsons mithilfe einer temporären Tabelle, die für eine relativ kleine Datenmenge (<1.000.000) ausreicht. Ich habe einen anderen Weg gefunden, bin dann aber in den Urlaub gefahren und habe ihn vergessen ...
So. Die Abfrage wird ungefähr so aussehen:
Es hat mehr mit String als mit Json zu tun, aber es funktioniert. Grundsätzlich werden alle Daten in eine temporäre Tabelle gezogen, eine Zeichenfolge erstellt, während Concat-Löcher mit den von Ihnen gesicherten Daten geschlossen werden, und in jsonb konvertiert.
Json_set ist vielleicht effizienter, aber ich verstehe es immer noch. Als ich das erste Mal versuchte, es zu benutzen, habe ich die Saite komplett durcheinander gebracht ...
quelle
Wenn Sie diese Abfrage mit einem Programmiersprachen-Client durchführen, z. B. von
python pycopg2
oderNode Postgres
, Stellen Sie sicher, dass Sie die neuen Daten zuerst in JSON analysieren.Es könnte leicht so aussehen, als wäre ein Python-Wörterbuch dasselbe wie ein JSON-Objekt, aber es führt nicht zuerst json.dumps im Wörterbuch aus.
Ein einfaches Python-Snippet:
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()
quelle