Добавление (перемещение) и удаление из массива JSON в PostgreSQL 9.5+

Для версий ниже 9.5 см. этот вопрос

Я создал таблицу в PostgreSQL, используя это:

CREATE TEMP TABLE jsontesting
AS
  SELECT id, jsondata::jsonb FROM ( VALUES
    (1, '["abra","value","mango", "apple", "sample"]'),
    (2, '["japan","china","india", "russia", "australia"]'),
    (3, '["must", "match"]'),
    (4, '["abra","value","true", "apple", "sample"]'),
    (5, '["abra","false","mango", "apple", "sample"]'),
    (6, '["string","value","mango", "apple", "sample"]'),
    (7, '["must", "watch"]')
  ) AS t(id,jsondata);

Теперь то, что я хотел, это

  • add Что-то вроде append_to_json_array принимает фактические jsondata, которые являются json-массивом, и newString, которые я должен добавить в этот массив jsondata, и эта функция должна возвращать обновленный json- множество.

    UPDATE jsontesting
    SET jsondata=append_to_json_array(jsondata, 'newString')
    WHERE id = 7;
    
  • удалить значение из массива данных json, одна функция для удаления значения.

Я попытался найти документацию PostgreSQL, но ничего там не нашел.


person Evan Carroll    schedule 14.02.2017    source источник


Ответы (2)


Чтобы добавить значение, используйте оператор добавления массива JSON (||)

UPDATE jsontesting
SET jsondata = jsondata || '["newString"]'::jsonb
WHERE id = 7;

Удаление значения выглядит так

UPDATE jsontesting
SET jsondata = jsondata - "newString"
WHERE id = 7; 

Объединение с вложенным полем выглядит так

UPDATE jsontesting
SET jsondata = jsonb_set(
  jsondata::jsonb,
  array['nestedfield'],
  (jsondata->'nestedfield')::jsonb || '["newString"]'::jsonb) 
WHERE id = 7;
person Evan Carroll    schedule 14.02.2017
comment
Какова производительность при добавлении к уже очень большим массивам? Нужно ли postgres загружать всю строку? - person ; 13.09.2017
comment
Каждый раз, когда вы обновляете столбец, PostgreSQL необходимо обновить всю строку. - person Evan Carroll; 13.09.2017
comment
не могли бы вы дать мне источник для этого? Я просто хотел бы прочитать немного больше об этом. - person ; 13.09.2017
comment
@Rollo что-нибудь MVCC. Так они все работают. Это решает проблему изоляции. Когда вы обновляете строку, эта строка не может быть видна ни одной транзакции до вашей фиксации, но она должна быть видна вашей собственной транзакции. Итак, вы записываете эту строку в таблице как мертвую строку. Когда вы делаете коммит, вы делаете его живым. Пока вы не зафиксируете, другие транзакции будут просматривать строку в ее предыдущем состоянии. - person Evan Carroll; 13.09.2017
comment
Там опечатка. SET jsondata = jsondata - "newString" должно быть SET jsondata = jsondata - '"newString"' - person Cody Canning; 25.06.2018
comment
еще лучше: SET jsondata = jsondata - 'newString' - person Cody Canning; 25.06.2018
comment
@Kostanos: Я сообщаю вам, что ваше редактирование было отменено здесь, на случай, если вы захотите обсудить это с Эваном. - person halfer; 11.08.2019
comment
Третий пример не совсем работает при использовании четвертого аргумента для создания вложенного массива, если он не существует. На самом деле в результате для столбца устанавливается значение null. Не могли бы вы добавить рабочий пример для этого случая? - person pomo; 04.03.2020
comment
Текущий ответ и документация помогли. - person Maxim Mandrik; 07.06.2020

Чтобы добавить к ответу Эвана Кэрролла, вы можете сделать следующее, чтобы установить столбец в пустой массив, если он равен NULL. Оператор добавления (||) ничего не делает, если столбец в настоящее время NULL.

UPDATE jsontesting SET jsondata = (
    CASE
        WHEN jsondata IS NULL THEN '[]'::JSONB
        ELSE jsondata
    END
) || '["newString"]'::JSONB WHERE id = 7;
person winduptoy    schedule 02.05.2017
comment
Я бы либо использовал объединение, либо написал бы это в условном выражении. - person Evan Carroll; 03.05.2017
comment
@EvanCarroll, не могли бы вы добавить пример, пожалуйста? - person ZiiMakc; 20.03.2019
comment
@RTW: postgresql и т. д. имеют встроенную функцию с именем coalesce, который делает то же самое, что и это выражение case. - person Håken Lid; 27.03.2019
comment
@RTW SET jsondata = COALESCE(jsondata, '[]'::JSONB) || '["newString"]'::JSONB - person Greg Hornby; 02.10.2019
comment
это должен быть лучший ответ ... Мне было интересно, почему он все еще равен нулю, и я подозревал это. проголосуйте, сэр. - person user299709; 28.11.2019