Обновить ключ объекта внутри массива объектов в столбце jsonb - PullRequest
0 голосов
/ 06 сентября 2018

У меня есть столбец jsonb с именем data. Он глубоко вложен, и есть ключ, значением которого является массив объектов:

select data#>>'{foo,bar,baz,qux}' from my_table limit 1;
-------------
?column? | [{"a": 1, "b:": 2}, {"a": 3, "b": 4}, {"a": 5, "b_": 6}]

Как видите, существуют различные формы клавиши "b".

Моя цель - обновить все строки с помощью клавиш "b:" и "b_" и установить для них "b".

1 Ответ

0 голосов
/ 06 сентября 2018

Этот ответ описывает способ переименования атрибута объекта json. Вы можете создать функцию, основанную на этой идее:

create or replace function jsonb_rename_attribute(obj jsonb, old_key text, new_key text)
returns jsonb language sql immutable as $$
    select obj - old_key || jsonb_build_object(new_key, obj->old_key)
$$;

и другая функция для облегчения модификации элементов массива json:

create or replace function jsonb_rename_attribute_in_array(arr jsonb, old_key text, new_key text)
returns jsonb language sql immutable as $$
    select jsonb_agg(
        case when value ? old_key 
            then jsonb_rename_attribute(value, old_key, new_key) 
            else value end)
    from jsonb_array_elements(arr);
$$;

Используйте функцию для обновления таблицы:

update my_table
set data = 
    jsonb_set(
        data, 
        '{foo,bar,baz,qux}', 
        jsonb_rename_attribute_in_array(
            jsonb_rename_attribute_in_array(
                data#>'{foo,bar,baz,qux}', 
                'b:', 'b'),
            'b_', 'b')
    )
where jsonb_typeof(data#>'{foo,bar,baz,qux}') = 'array';

Рабочий пример в rextester.

Примерный триггер перед вставкой:

create or replace function before_insert_on_my_table()
returns trigger language plpgsql as $$
begin
    if jsonb_typeof(new.data#>'{foo,bar,baz,qux}') = 'array' then
        new.data = 
            jsonb_set(
                new.data, 
                '{foo,bar,baz,qux}', 
                jsonb_rename_attribute_in_array(
                    jsonb_rename_attribute_in_array(
                        new.data#>'{foo,bar,baz,qux}', 
                        'b:', 'b'),
                    'b_', 'b')
            );
    end if;
    return new;
end $$;

create trigger before_insert_on_my_table
before insert on my_table
for each row execute procedure before_insert_on_my_table();
...