【问题标题】:Postgres/JSON - update all array elementsPostgres/JSON - 更新所有数组元素
【发布时间】:2017-02-16 14:37:03
【问题描述】:

给定以下 json:

{
  "foo": [
    {
      "bar": true
    },
    {
      "bar": true
    }
  ]
}

如何选择以下内容:

{
  "foo": [
    {
      "bar": false
    },
    {
      "bar": false
    }
  ]
}

?

到目前为止,我已经弄清楚了如何操作单个数组值:

SELECT
  jsonb_set(
    '{
      "foo": [
        {
          "bar": true
        },
        {
          "bar": true
        }
      ]
    }'::jsonb, '{foo,0,bar}', to_jsonb(false)
  )

但是如何在数组中设置所有元素?

【问题讨论】:

    标签: arrays json postgresql jsonb


    【解决方案1】:

    您可能想用一块石头杀死两只鸟 - 更新数组中每个对象中的现有键或插入具有给定值的键。 jsonb_set 在这里完美匹配,但是它需要我们传递每个对象的索引,所以我们必须先遍历数组。

    该实现受到 klin 的回答的极大启发,它没有解决我的问题(更新和插入)并且如果对象中有多个键则不起作用。 所以,实现如下:

    -- the params are the same as in aforementioned `jsonb_set`
    CREATE OR REPLACE FUNCTION update_array_elements(target jsonb, path text[], new_value jsonb)
      RETURNS jsonb language sql AS $$
        -- aggregate the jsonb from parts created in LATERAL
        SELECT jsonb_agg(updated_jsonb)
        -- split the target array to individual objects...
        FROM jsonb_array_elements(target) individual_object,
        -- operate on each object and apply jsonb_set to it. The results are aggregated in SELECT
        LATERAL jsonb_set(individual_object, path, new_value) updated_jsonb
      $$;
    

    就是这样...... :)

    我希望它能帮助遇到同样问题的人。

    【讨论】:

      【解决方案2】:

      没有标准的函数来按键更新json数组元素。 自定义函数可能是解决问题的最简单方法:

      create or replace function update_array_elements(arr jsonb, key text, value jsonb)
      returns jsonb language sql as $$
          select jsonb_agg(jsonb_build_object(k, case when k <> key then v else value end))
          from jsonb_array_elements(arr) e(e), 
          lateral jsonb_each(e) p(k, v)
      $$;
      
      select update_array_elements('[{"bar":true},{"bar":true}]'::jsonb, 'bar', 'false');
      
            update_array_elements
      ----------------------------------
       [{"bar": false}, {"bar": false}]
      (1 row)
      

      您的查询可能如下所示:

      with a_data(js) as (
      values(
          '{
              "foo": [
                {
                  "bar": true
                },
                {
                  "bar": true
                }
              ]
          }'::jsonb)
      )
      select
          jsonb_set(js, '{foo}', update_array_elements(js->'foo', 'bar', 'false'))
          from a_data;
      
                       jsonb_set                 
      -------------------------------------------
       {"foo": [{"bar": false}, {"bar": false}]}
      (1 row)     
      

      【讨论】:

        猜你喜欢
        • 2021-04-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-20
        • 1970-01-01
        • 2018-05-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多