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

如何修改PostgreSQL JSONB数据类型中的单个属性值?,json,postgresql,jsonb,Json,Postgresql,Jsonb,如何修改PostgreSQL JSONB数据类型中的单个字段 假设我有一张叫做动物的桌子,像这样: id info ------------------------------------------------------------ 49493 {"habit1":"fly","habit2":"dive","location":"SONOMA NARITE"} 我只想简单地更改location属性的值(比如,文本大小写)。因此,更新后的结果是 id i

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

假设我有一张叫做动物的桌子,像这样:

id       info
------------------------------------------------------------
49493   {"habit1":"fly","habit2":"dive","location":"SONOMA NARITE"}
我只想简单地更改location属性的值(比如,文本大小写)。因此,更新后的结果是

    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集合函数并没有提供这样一个简单的操作,即只尝试更新jsonb中文本属性的大小写


有人能帮忙吗?

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


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;

我想在这里分享一些好消息。多亏了克林,他的投入帮助我发现了这个解决方案。在上面的例子中。如果我只是使用concat函数,那么我在klin发布的代码中发现的问题就得到了解决(简而言之,它只在文本值包含空格时才起作用)。现在我可以降低单个属性值的大小写

UPDATE test1 set info=jsonb_set(info, '{location}', concat('"',lower(info->>'locatioin'),'"')::jsonb, true) returning *;

谢谢克林,我会试试看,然后告诉你。我的查询中没有标记“someooopath”。我无法调试一个我看不到的查询…嗨,克林,我想我发现了一个问题,它不起作用。假设上面示例中的“location”属性中有下划线。postgres将抛出类似“类型json的输入语法无效”的错误。或者如果此属性的值中没有空格。它也会抛出错误信息列下的这个值不起作用{“位置”:“实体模型属性”}#信息列下的这个值也不起作用{“位置”:“实体模型属性”}#信息列下的这个值将起作用{“位置”:“实体模型属性”}是的,你是对的。在这些情况下,
quote_ident()
不是一个好的选择。改用
concat()
format()
。请看修改后的答案。嗨,克林,我遇到了另一个问题。我的开发机器有Postgres v9.6,它有jsonb_集功能,但我们的生产服务器使用的是Postgres v9.4.5,它没有jsonb_集功能。所以我不能用这个脚本。如果你不介意的话,你能帮我一下还是给我一些建议?谢谢我尝试更新test_table set info=jsonb_set(info,{location},''cityTest',true),其中id='123';但由于函数不存在,它仍然给出错误。我正在使用postgresql 9.4.8
UPDATE test1 set info=jsonb_set(info, '{location}', concat('"',lower(info->>'locatioin'),'"')::jsonb, true) returning *;