Postgresql:从 json 值的嵌套数组字段编辑特定字段

Postrgesql : Edit a specific field from a nested array field of a jsonb value

table:

table Bar(
  id int,
  my_json jsonb
)

my_json 的示例:

{
  "foo": "bar",
  "columns": [
    {
      "type": "integer",
      "field": "myField",
      "children": [
        {
          "type": "integer",
          "field": "myField"
        }
      ]
    },
    {
      "type": "integer",
      "field": "otherField",
      "children": [
        {
          "type": "integer",
          "field": "myField"
        }
      ]
    },
    {
      "type": "integer",
      "field": "baz",
      "children": null
    }
  ]
}

我需要将所有 "type": "integer" 更改为 "type": "string",其中匹配的 "field" 等于 "myField"

我用下一个 sql 查询制作了 lvl 1(在 columns lvl):

with query as (
    select ('{columns,' || index - 1 || ',type}')::text[] as path,
           b.id
    from Bar b,
         jsonb_array_elements(my_json -> 'columns') with ordinality arr(col, index)
    where col ->> 'field' = 'myField'
      and col ->> 'type' = 'integer'
)
update Bar b
set my_json = jsonb_set(b.my_json, query.path, '"string"', false)
from query
where b.id = query.id;

我必须使用可能为 null 的嵌套数组 children 达到 2 级(理想情况下理解任何级别),但我不知道该怎么做。

我做到了!这是我找到的解决方案:

with non_null_children as (
    select index - 1 as idx,
           col,
           b.id as bar_id
    from Bar b,
         jsonb_array_elements(my_json -> 'columns') with ordinality arr(col, index)
    where col ->> 'children' is not null
), query as (
    select ('{columns,' || nnc.idx || ',children,' || index - 1 || ',type}')::text[] as path,
           b.id
    from Bar b,
         non_null_children nnc,
         jsonb_array_elements(nnc.col -> 'children') with ordinality arr(col2, index)
    where b.id = nnc.bar_id
      and col2 ->> 'field' = 'myField'
      and col2 ->> 'type' = 'integer'
)
update Bar b
set my_json = jsonb_set(b.my_json, query.path, '"string"', false)
from query
where b.id = query.id;

解释:

  • 我列出了所有包含子项的项目,每个项目都与其 columns 索引及其 Bar id -> non_null_children
  • 对于每个Bar id / column index,我可以进行匹配字段操作,就像lvl 1一样。

不知道这是不是最优化的方案,如果觉得有必要,欢迎改进。