Обновление : в PostgreSQL 9.5 есть некоторые jsonb
функциональные возможности манипулирования внутри самого PostgreSQL (но не для 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)
path
может содержать индексы массивов JSON и отрицательные целые числа, которые там появляются, считаются с конца массивов 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)
Опять же, отрицательные целые числа, которые появляются в path
счетчике с конца массивов JSON.
Так, например добавление в конец массива 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
in 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()
.
Оригинальный ответ : Это возможно (без plpython или plv8) и в чистом SQL (но требует 9.3+, не будет работать с 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
Редактировать :
Версия, которая устанавливает несколько ключей и значений:
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$;
Обновление : функции теперь сжаты.
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"
UPSERT
, а неUPDATE
. Если ключ еще не существует в поле json, он добавляется. Посмотрите на этот связанный вопрос для фактическогоUPDATE
: stackoverflow.com/questions/7711432/… (Это для составного типа, но принципал похож на json.)$2::text
.С 9.5 используйте jsonb_set-
где body это тип столбца jsonb.
источник
upper
:update objects set body=jsonb_set(body, '{name}', upper('"Mary"'), true) where id=1;
он не распознает, или как я могу добиться того же поведения? спасибоС Postgresql 9.5 это можно сделать, выполнив
ИЛИ
Кто-то спрашивал, как обновить сразу несколько полей в значении jsonb. Предположим, мы создали таблицу:
Затем мы вставляем экспериментальный ряд:
Затем мы ОБНОВЛЯЕМ строку:
Что делает следующее:
Выбор данных:
Приведет к:
Чтобы обновить поле внутри, не используйте оператор concat
||
. Вместо этого используйте jsonb_set. Что не простоИспользуя оператор concat для {c, c1}, например:
Удалит {c, c2} и {c, c3}.
Чтобы получить больше возможностей, обратитесь к документации по функциям postgresql json . Кто-то может быть заинтересован в
#-
операторе,jsonb_set
функции, а такжеjsonb_insert
функции.источник
UPDATE users SET profile = profile || '{"lastname":"Washington"}' WHERE profile->>'name' = 'George Washington';
Чтобы воспользоваться ответами @ pozs, вот еще пара функций PostgreSQL, которые могут быть полезны для некоторых. (Требуется PostgreSQL 9.3+)
Удалить по ключу: удаляет значение из структуры JSON по ключу.
Рекурсивное удаление по ключу: удаляет значение из структуры JSON по ключу-пути. (требуется
json_object_set_key
функция @ pozs )Примеры использования:
источник
Кажется, это работает на PostgreSQL 9.5
источник
Если ваш тип поля имеет тип json, вам подойдет следующее.
Оператор '-' удаляет пару ключ / значение или строковый элемент из левого операнда. Пары ключ / значение сопоставляются на основе их значения ключа.
Оператор '||' объединить два значения jsonb в новое значение jsonb.
Так как это операторы jsonb, вам просто нужно ввести тип :: jsonb
Дополнительная информация: функции и операторы JSON
Вы можете прочитать мою заметку здесь
источник
В PostgreSQL 9.4 мы реализовали следующую функцию python. Он также может работать с PostgreSQL 9.3.
Пример использования:
Обратите внимание, что для предыдущего работодателя я написал набор функций C для управления данными JSON в виде текста (а не типа
json
илиjsonb
типа) для PostgreSQL 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 дней, поэтому, если вам нужно, чтобы она работала на устаревших системах, и у вас было время, чтобы сэкономить, это может стоить усилий. Я представляю, что версия C намного быстрее, чем версия Python.источник
Это сработало для меня, когда я пытался обновить поле типа строки.
Надеюсь, это поможет кому-то еще!
Предполагая, что таблица table_name имеет столбец jsonb с именем body, и вы хотите изменить body.some_key = 'value'
источник
Даже если следующее не удовлетворит этот запрос (функция json_object_agg недоступна в PostgreSQL 9.3), следующее может быть полезно любому, кто ищет || оператор для PostgreSQL 9.4, реализованный в следующем PostgreSQL 9.5:
источник
Я написал небольшую функцию для себя, которая работает рекурсивно в Postgres 9.4. Вот функция (надеюсь, она вам подходит):
Вот пример использования:
Как вы можете видеть, он анализирует в глубине и обновляет / добавляет значения, где это необходимо.
источник
К сожалению, я ничего не нашел в документации, но вы можете использовать какой-то обходной путь, например, вы можете написать некоторую расширенную функцию.
Например, в Python:
а потом
источник
value
будет требоватьсяloads
при установке нечисловых значений, таких как strings (js[key] = loads(value)
) - В противном случае:select json_update('{"a":"a"}', 'a', to_json('b')); -> {"a": "\"b\""}
Следующий фрагмент кода plpython может пригодиться.
источник
Я обнаружил, что предыдущие ответы подходят опытным пользователям PostgreSQL, поэтому мой ответ:
Предположим, у вас есть таблица-столбец типа JSONB со следующим значением:
давайте предположим, что мы хотим установить новое значение в строке:
и вместо этого поместите значение:
мы используем функцию json_set (), чтобы назначить новое значение для ключа13
параметры для jsonb_set ()
в " target " - я помещу имя столбца jsonb (это столбец таблицы, который изменяется)
« путь » - это «путь ключей json», ведущий (и включающий) ключ, который мы собираемся перезаписать
« new_value » - это новое значение, которое мы назначаем
в нашем случае мы хотим обновить значение key13, которое находится в key1 (key1 -> key13):
следовательно, синтаксис пути : '{key1, key13}' (путь был самым сложным для взлома, потому что учебники ужасны)
источник
Вы также можете увеличивать ключи атомарно внутри
jsonb
следующим образом:Неопределенный ключ -> принимает начальное значение 0.
Для более подробного объяснения, смотрите мой ответ здесь: https://stackoverflow.com/a/39076637
источник
Для тех, кто использует
mybatis
, вот пример заявления об обновлении:Params:
qid
Ключ для поля.value
, является допустимой строкой json, для значения поля,например, преобразованной из объекта в строку json через
jackson
,источник
Так, например, моя строка выглядит следующим образом: {"a1": {"a11": "x", "a22": "y", "a33": "z"}}
Я обновляю jsons, используя временную таблицу, что достаточно для довольно небольшого количества данных (<1.000.000). Я нашел другой путь, но потом ушел в отпуск и забыл об этом ...
Так. запрос будет примерно таким:
Это больше связано со строкой, чем с JSON, но работает. По сути, он вытягивает все данные во временную таблицу, создает строку, в то же время подключая конкатные дыры с данными, для которых вы создали резервную копию, и преобразует их в jsonb.
Json_set может быть более эффективным, но я все еще изучаю его. В первый раз, когда я пытался его использовать, я перепутал строку полностью ...
источник
Если вы делаете этот запрос с помощью клиента языка программирования, например, из
python pycopg2
илиNode Postgres
, убедитесь, что сначала вы анализируете новые данные в JSON.Может показаться, что словарь python - это то же самое, что и объект JSON, но сначала он не выполняет json.dumps в словаре.
Простой фрагмент кода Python:
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()
источник