【问题标题】:How to update objects in a JSON array based on a specific key/value pair in Postgres如何根据 Postgres 中的特定键/值对更新 JSON 数组中的对象
【发布时间】:2020-10-02 01:17:41
【问题描述】:

我的数据如下所示:

id  name    blocks
1   Test 1  [{"name": "Bob", "type": "INFO", "title": "CFO"}, {"type": "FOOTER"}]
2   Another [{"name": "Bob", "type": "INFO", "title": "Manager"}, {"type": "FOOTER"}]
3   Final   [{"id": 22, "type": "IMAGE"}]

用户可能想在所有行中更改他们的名称,所以我需要一个 Postgres JSON 版本:

UPDATE blocks SET name = 'New Name' WHERE type = 'INFO';

如何编写一个查询来搜索这些对象数组以查找特定的 type 键值 "INFO"?这里最大的问题是这些对象可以在数组中以任何顺序排列。所以INFO 块不一定总是在索引 0 处。

【问题讨论】:

  • 您要更新哪个name。数组元素中的名称归档或名称标记
  • @AkhileshMishra 我想用新名称更新名称,只要对象具有值type = 'INFO'

标签: sql json postgresql


【解决方案1】:

这最终是我所采用的(基于接受的答案),只是稍微清理了一下并使用真实的表名和 JSONB 结构命名。这也确保用户只能批量更新他们自己的数据,而不是其他人的。

WITH new_data AS (
  SELECT id, json_agg(
    CASE
      WHEN blocks.block->>'type' = 'CONTACT_INFO'
        THEN jsonb_set(blocks.block, '{data, name}', '"New Name"', false)
      ELSE
        blocks.block
    END) AS new_block
  FROM reels
  CROSS JOIN LATERAL jsonb_array_elements(blocks) blocks(block)
  WHERE owner_id = '9292dcc6-f906-418a-aee0-074b297bfb52'
  GROUP BY id
)
UPDATE reels
SET blocks = new_data.new_block
FROM new_data
WHERE reels.id = new_data.id;

【讨论】:

    【解决方案2】:

    您的示例中有 2 个name 字段。

    如果您想使用您的条件更新json 字段中的name 标记,请尝试以下查询:

    with cte as 
    (
    select 
    id,
    name,
    json_agg(case when t.x->>'type'='INFO' then jsonb_set(t.x,'{name}','"New Name"',false) else t.x end) "new_value"
    from blocks cross join lateral jsonb_array_elements(blocks::jsonb) t(x)
    group by 1,2
    )
    update blocks t1 
    set blocks=t2.new_value
    from cte t2 
    where t1.id=t2.id;
    

    DEMO

    如果您想根据您的条件更新表的 name 字段,请尝试以下查询:

    with cte as 
    (
    select 
    id,
    name,
    bool_or(t.x->>'type'='INFO') "new_value"
    from blocks cross join lateral jsonb_array_elements(blocks::jsonb) t(x)
    group by 1,2
    )
    update blocks t1 
    set name='New Name'
    from cte t2 
    where t1.id=t2.id and t2.new_value=true;
    

    DEMO

    【讨论】:

    • 谢谢!!第一个是我需要的。不过我真的不明白..我必须更多地研究 Postgres。
    猜你喜欢
    • 2019-04-01
    • 2021-10-06
    • 1970-01-01
    • 2022-12-01
    • 1970-01-01
    • 2021-03-05
    • 1970-01-01
    • 2021-11-29
    • 2022-08-13
    相关资源
    最近更新 更多