在jsonb列中的对象数组内更新对象的键

时间:2018-09-06 09:24:42

标签: sql postgresql jsonb

我有一个名为jsonb的{​​{1}}列。它是深层嵌套的,并且有一个键,其值是对象数组:

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

1 个答案:

答案 0 :(得分:1)

This answer描述了重命名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';

Working example in 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();