【问题标题】:Update key of object inside array of objects in jsonb column更新 jsonb 列中对象数组内对象的键
【发布时间】:2018-09-06 19:27:35
【问题描述】:

我有一个名为datajsonb 列。它嵌套很深,并且有一个键,它的值是一个对象数组:

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"

【问题讨论】:

    标签: sql postgresql jsonb


    【解决方案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();
    

    【讨论】:

    • 这太棒了!
    • 一个问题:将这个函数添加到我的架构中,现在当新行出现时,这个函数会自动工作(更新“坏”键)吗?还是需要触发器什么的?
    • 该函数不会自动调用,但您可以将其置于触发器中。
    • 查看更新后的答案。另请注意,我添加了更新查询中可能需要的 where 子句。
    • jsonb_array_elements() 返回value(作为连续的数组元素)。见the documentation.中的描述
    猜你喜欢
    • 2018-11-15
    • 1970-01-01
    • 2020-12-09
    • 1970-01-01
    • 2018-06-30
    • 2021-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多