json - 如何修改 PostgreSQL JSONB 数据类型中的单个属性值?

标签 json postgresql jsonb

如何修改 PostgreSQL JSONB 数据类型中的单个字段?

假设我有一个这样的名为 animal 的表:

id       info
------------------------------------------------------------
49493   {"habit1":"fly","habit2":"dive","location":"SONOMA NARITE"}

我只想更改位置属性的值(例如,将文本更改为大写或小写)。所以更新后的结果是

    id       info
------------------------------------------------------------
49493   {"habit1":"fly","habit2":"dive","location":"sonoma narite"}

下面这个我试过了,还是不行

update animal set info=jsonb_set(info, '{location}', LOWER(info->>'location'), true) where id='49493';
----------------------------------
ERROR:  function jsonb_set(jsonb, unknown, text, boolean) does not exist
LINE 7: update animal set info=jsonb_set(info, '{con...
                                           ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
********** Error **********

ERROR: function jsonb_set(jsonb, unknown, text, boolean) does not exist

如果我只知道更新后的值是多少,那么我可以使用这个:

update animal set info=jsonb_set(info, '{location}', '"sonoma narite"', true) where id='49493';

但是,如果文本值是未知的,我们只是想做一些简单的操作,比如追加、前置、大小写,我不能简单地找到答案。

令我感到惊讶的是,jsonb set 函数没有提供这种仅尝试更新 jsonb 中文本属性大小写的简单操作。

有人可以帮忙吗?

最佳答案

jsonb_set()的第三个参数应该是jsonb类型。问题是在将文本字符串转换为 jsonb 字符串时,您需要用双引号引起来的字符串。您可以使用 concat()format():

update animal
set info = 
    jsonb_set(info, '{location}', concat('"', lower(info->>'location'), '"')::jsonb, true) 
--  jsonb_set(info, '{location}', format('"%s"', lower(info->>'location'))::jsonb, true) 
where id='49493'
returning *;

  id   |                               info                               
-------+------------------------------------------------------------------
 49493 | {"habit1": "fly", "habit2": "dive", "location": "sonoma narite"}
(1 row)

Postgres 9.4 中,您应该使用 jsonb_each_text() 取消嵌套 json 列,聚合键和值动态修改正确的值,最后构建一个 json 对象:

update animal a
set info = u.info
from (
    select id, json_object(
        array_agg(key), 
        array_agg(
            case key when 'location' then lower(value)
            else value end))::jsonb as info
    from animal,
    lateral jsonb_each_text(info) 
    group by 1
    ) u
where u.id = a.id
and a.id = 49493;

如果您可以创建函数,这个解决方案可能会更令人愉快:

create or replace function update_info(info jsonb)
returns jsonb language sql as $$
    select json_object(
        array_agg(key), 
        array_agg(
            case key when 'location' then lower(value)
            else value end))::jsonb
    from jsonb_each_text(info)
$$

update animal
set info = update_info(info)
where id = 49493;

关于json - 如何修改 PostgreSQL JSONB 数据类型中的单个属性值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41902278/

相关文章:

javascript - 由于点 ID 导致 JSON 调用出错

ios - 将 AnyObject/NSDictionary (JSON) 转换为字符串?

ios - 在将其解析为 JSON 文件 Swift 后声明类型

ruby-on-rails - rake 数据库 :create gives error on server

postgresql - 结合其他列对 JSONB 键建立索引

java - Jackson 中的序列化数组类型和数组

sql - 如何重写使用聚合函数和分组依据的查询

python - Django 不以存储格式返回日期时间值

sql - 如何查询 jsonb 数组以查找它是否包含查询列表中的值?

Postgresql - 来自 jsonb 数组的不同值