在Postgres中向JSON对象添加元素

时间:2012-11-28 22:43:11

标签: json string postgresql select replace

我在数据库(postgres 9.2.1)中有一个文本字段,其中包含一个json blob。它看起来与此类似,除了所有在一条线上,显然:

{
  "keyword": {
    "checked": "1",
    "label": "Keyword"
  },
  "agency_name": {
    "checked": "0",
    "label": "Agency Name"
  }
}

我需要在json数组中添加一个元素,使它看起来像这样:

{
  "keyword": {
    "checked": "1",
    "label": "Keyword"
  },
  "something_new": {
    "checked": "1",
    "label": "Something New"
  },
  "agency_name": {
    "checked": "0",
    "label": "Agency Name"
  }
}

我并不关心新数组元素的位置。它可以在agency_name之后。在postgres中有一个简单的方法吗?

7 个答案:

答案 0 :(得分:13)

如果升级到PG9.5.1,那么你可以使用sql操作||来合并jsonb,例如

select '{"a":1}'::jsonb || '{"a":2, "b":2}'::jsonb

将返回{"a": 2, "b": 2}

如果你无法升级到pg9.5.1,恕我直言,在你的代码中完成工作将是一个更好的选择。您可以将旧的jsonb字符串解析为映射,然后更新映射,然后转换为字符串并更新db-record。

答案 1 :(得分:7)

即使我有同样的问题,我也想动态地将新元素附加到jsonb []。

  

假设column_jsonb [] = [{“name”:“xyz”,“age”:“12”}]

UPDATE table_name
   SET column_jsonb[] = array_append(column_jsonb[],'{"name":"abc","age":"22"}');

结果:[{“name”:“xyz”,“age”:“12”},{“name”:“abc”,“age”:“22”}]

答案 2 :(得分:5)

PostgreSQL对JSON支持函数的影响还不多:我所能看到的只有array_to_json,如果有相应的方法将原始JSON转换为数组,这可能很有用,然后,您可以在转换回JSON之前操作添加该附加元素。

可能最好的事情是使用PL语言来操纵JSON。一个显而易见的是PLV8,它在PostgreSQL中提供JavaScript编程功能。您将在JavaScript中编写一个用户定义的函数,该函数将相应地操作JSON blob:

当然,许多其他PL语言(如Java,Python或Perl)在处理JSON数据方面也同样出色,并且可能更容易在您的系统上安装。如果您已经设置了用户定义的函数,可以在每个函数中编写。

答案 3 :(得分:4)

使用||合并jsonb并将其值设置为

示例:

来源:

在表a中:

  

id |信息

     

1 | {“ aa”:“ bb”}

     

2 | {“ aa”:“ cc”}

执行后:

update a set info = info::jsonb || ('{"id":}' || id || '}' )::jsonb 

生成:

  

id |信息

     

1 | {“ aa”:“ bb”,“ id”:1}

     

2 | {“ aa”:“ cc”,“ id”:2}

something_else:

  1. 使用- ‘key’删除jsonb中的元素
  2. 如果两个jsonb具有相同的密钥,
  3. 合并将替换原点一

答案 4 :(得分:2)

Version 9.5提供了jsonb_set函数,create_missing = TRUE。 在任何其他情况下,使用以下hack来附加信息:

SELECT (trim( trailing '}' from data::text) || ', "c":2}')::json

使用更正确的方式添加/替换新值:

UPDATE t
SET data=t3.data

FROM t AS t1
INNER JOIN
(
  SELECT id, json_object_agg(t.k,t.v)
  FROM
    (
      SELECT *
      FROM (SELECT id, json_object_keys(data) as k, data->json_object_keys(data) as v FROM t) as t2
      WHERE t.k != 'c'

      UNION ALL
      SELECT id, 'c'::text as k, '"new value"'::json as v FROM t1
    ) as t3
  GROUP by id
) as t4 ON (t1.id=t4.id)

删除密钥:

UPDATE t
SET data=t3.data

FROM t AS t1
INNER JOIN
(
  SELECT id, json_object_agg(t.k,t.v)
  FROM (SELECT id, json_object_keys(data) as k, data->json_object_keys(data) as v FROM t) as t2
  WHERE t.k != 'c'
  GROUP by id
) as t4 ON (t1.id=t4.id)

答案 5 :(得分:1)

我确实遇到了这个问题。这个解决方案非常纯净。对象操作,我更喜欢' sql' plpgsql的函数。主要的是使用json_each进行分解 - 给你一条记录 - 然后从

创建一条记录
CREATE OR REPLACE FUNCTION json_extend_object(
    input_object json,
    append_key text,
    append_object json)
  RETURNS json AS
$BODY$
    select json_object_agg (((json_val)::record).key, ((json_val)::record).value)
    from (
        select json_val 
        from (select json_each (input_object) as json_val) disaggr
        where ((json_val::record).key != append_key)
        union 
        select newvals
        from (
            select append_key, append_object
        ) newvals
    ) to_rows;
$BODY$
  LANGUAGE sql IMMUTABLE
  ;

答案 6 :(得分:1)

安德鲁·沃尔夫(Andrew Wolfe)提供的解决方案很好,但与<9.4以下的postgres版本不兼容。如果您使用的是9.4+版本,则只需使用jsonb和|| (并置)运算符,将元素添加到json。

因此,这是json_extend_object的9.3兼容版本:

CREATE OR REPLACE FUNCTION json_extend_object(
    input_object json,
    append_key text,
    append_object json)
  RETURNS json AS
$BODY$
    select ('{'||string_agg(''||to_json((json_val::record).key)||':'|| to_json((json_val::record).value), ',')||'}')::json
    from (
        select json_val 
        from (select json_each (input_object) as json_val) jsonvals
        where ((json_val::record).key != append_key)
    union 
        select newvals
        from (select append_key, append_object) newvals
    ) to_rows;
$BODY$
LANGUAGE sql IMMUTABLE;