在 jsonb 中将值从数组更改为字符串

Change value from array to string in jsonb

有这样一个jsonb:

{
  "name": "Somedata",
  "attr": [
    {
      "type": "string",
      "otherdata": null,
      "info": "4cf1c0de-4ea5-439e-82be-efcf22b5c401",
    },
    {
      "type": "date",
      "otherdata": null,
      "info": [
      "eaffa971-ee96-4944-8145-4c5defa3cb2c",
      ]
    },
    {
      "type": "date",
      "otherdata": null,
      "info": "7c15ffcd-2011-4d73-8d05-65c70dab3302",
    }
  ]
}

需要搜索存在“attr”键的所有条目,并且 找到所有具有数组值的“信息”键, 并将值从数组更改为字符串。

预期结果:

{
  "name": "Somedata",
  "attr": [
    {
      "type": "string",
      "otherdata": null,
      "info": "4cf1c0de-4ea5-439e-82be-efcf22b5c401",
    },
    {
      "type": "date",
      "otherdata": null,
      "info": "eaffa971-ee96-4944-8145-4c5defa3cb2c",
    },
    {
      "type": "date",
      "otherdata": null,
      "info": "7c15ffcd-2011-4d73-8d05-65c70dab3302",
    }
  ]
}

我对 jsonb_array_elements、jsonb_set 的操作没有导致任何结果..

使用 PostgreSQL 12.3 和 13.4

Demo

select
  t.id,
  t.data || jsonb_build_object(
    'attr',
    jsonb_agg(
      case 
        when jsonb_typeof(e.value -> 'info') = 'array' then jsonb_set(e.value, '{info}',  coalesce(e.value -> 'info' -> 0, 'null'))
        else e.value
      end
    )
  )
from
  test t
  cross join jsonb_array_elements(t.data -> 'attr') e
where
  t.data ? 'attr'
group by t.id, t.data

P.S:

如果您需要更新记录,您可以使用以下查询:

update test u_t
set data = tmp.change_data
from (
  select
    t.id,
    t.data || jsonb_build_object(
      'attr',
      jsonb_agg(
        case 
          when jsonb_typeof(e.value -> 'info') = 'array' then jsonb_set(e.value, '{info}',  coalesce(e.value -> 'info' -> 0, 'null'))
          else e.value
        end
      )
    ) as change_data
  from
    test t
    cross join jsonb_array_elements(t.data -> 'attr') e
  where
    t.data ? 'attr'
  group by t.id, t.data
) tmp
where
  u_t.id = tmp.id;