arrays - PostgreSQL:更新 JSONB 结构内嵌套数组中元素的属性

标签 arrays json postgresql jsonb postgresql-json

我在 PostgreSQL 9.6 中有一个 jsonb 结构,它包含一个类似于下面示例的嵌套数组结构:

continents:[
   {
       id: 1,
       name: 'North America',
       countries: [
           {
               id: 1,
               name: 'USA',
               subdivision: [
                  {
                     id: 1,
                     name: 'Oregon',
                     type: 'SOME_TYPE'
                  }
               ]
           } 
       ]
   }
]

如何更改多个分割的“类型”属性,因为它嵌套在两个数组(国家/地区分割)中?

我遇到了其他答案,并且能够逐条记录地这样做(假设表是 ma​​p 并且 jsonb 列是 divisions ):

update map
set divisions = jsonb_set( divisions, '{continents,0,countries,0,subdivisions,0,type}', '"STATE"', FALSE);

有没有办法以编程方式更改所有分割的该属性?

我想我已经接近了,我可以使用下面的查询查询所有分割类型,但我正在努力弄清楚如何更新它们:

WITH subdivision_data AS (
    WITH country_data AS (
       select continents -> 'countries' as countries
       from  map, jsonb_array_elements( map.divisions -> 'continents' ) continents
    )
    select country_item -> 'subdivisions' as subdivisions
    from country_data cd, jsonb_array_elements( cd.countries ) country_item
)
select subdivision_item ->> 'type' as subdivision_type
from subdivision_data sub, jsonb_array_elements( sub.subdivisions ) subdivision_item;

以下是我遇到的一些问题。它们似乎只有在您尝试更新单级数组时才有效:

postgresql 9.5 using jsonb_set for updating specific jsonb array value

How to update deeply nested JSON object based on filter criteria in Postgres?

Postgres/JSON - update all array elements

最佳答案

起初我认为这样的事情会起作用:

update map as m set
    divisions = jsonb_set(m1.divisions, array['continents',(d.rn-1)::text,'countries',(c.rn-1)::text,'subdivisions',(s.rn-1)::text,'type'], '"STATE"', FALSE)
from map as m1,
    jsonb_array_elements(m1.divisions -> 'continents') with ordinality as d(data,rn),
    jsonb_array_elements(d.data -> 'countries') with ordinality as c(data,rn),
    jsonb_array_elements(c.data -> 'subdivisions') with ordinality as s(data,rn)
where
    m1.id = m.id

db<>fiddle demo

但这不起作用 - 请参阅 documentation

When a FROM clause is present, what essentially happens is that the target table is joined to the tables mentioned in the from_list, and each output row of the join represents an update operation for the target table. When using FROM you should ensure that the join produces at most one output row for each row to be modified. In other words, a target row shouldn't join to more than one row from the other table(s). If it does, then only one of the join rows will be used to update the target row, but which one will be used is not readily predictable.

你可以做的是用 functions-json 取消嵌套你的 jsons然后将它们聚合回来:

update map set
    divisions = jsonb_set(divisions, array['continents'],
        (select
            jsonb_agg(jsonb_set(
                d, array['countries'],
                (select 
                    jsonb_agg(jsonb_set(
                        c, array['subdivisions'],
                        (select
                            jsonb_agg(jsonb_set(s, array['type'], '"STATE"', FALSE))
                        from jsonb_array_elements(c -> 'subdivisions') as s),
                        FALSE
                    ))
                from jsonb_array_elements(d -> 'countries') as c)
            ))
        from jsonb_array_elements(divisions -> 'continents') as d),
        FALSE
    )

db<>fiddle demo

您还可以创建可以用来代替多个子查询的辅助函数:

create function jsonb_update_path(_data jsonb, _path text[], _value jsonb)
returns jsonb
as $$
begin
    if array_length(_path, 1) = 1 then
        return jsonb_set(_data, _path, _value, FALSE);
    else
        return (
            jsonb_set(
                _data, _path[1:1],
                (
                    select
                        jsonb_agg(jsonb_update_path(e, _path[2:], _value))
                    from jsonb_array_elements(_data -> _path[1]) as e
                )
            )
        );
    end if;
end
$$
language plpgsql

update map set
    divisions = jsonb_update_path(divisions, '{continents,countries,subdivisions,type}', '"STATE"')

db<>fiddle demo

关于arrays - PostgreSQL:更新 JSONB 结构内嵌套数组中元素的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55697028/

相关文章:

json - Azure Durable Functions我应该如何处理TaskFailedExceptionDeserializationException

java - 如何在 Json 树中按名称查找节点?

sql - 如何在 Hibernate 中使用数组字段创建条件

arrays - Powershell 匹配属性,然后有选择地组合对象以创建第三个对象

c# - ServiceStack JsonSerializer 继承时不序列化对象成员

arrays - Swift:代码由于某种原因崩溃

python - 适用于 Linux 的 Windows 子系统 2 : Ubuntu, 连接到外部 PostgreSQL 数据库

java - Liquibase 错误 [Postgresql] : unterminated dollar-quoted string at or near "$BODY$

javascript - 如何根据子条件JS从数组中删除对象

python - Numpy Broadcasting Answer 的解释