33

我在数据库(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"
  }
}

我不关心新数组元素的位置。它可能在机构名称之后。在 postgres 中是否有一种简单的方法可以做到这一点?

4

7 回答 7

40

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

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

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

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

如果我们想更新(添加)一个 JSONB 字段:

UPDATE <table>
SET <field-name> = <field-name> || '{"a": 1}'::jsonb
WHERE id = <some id>
于 2016-03-04T07:10:39.203 回答
16
于 2018-08-28T10:00:13.933 回答
10

即使我遇到了同样的问题,我也想动态地将新元素附加到 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"}]

于 2016-07-06T16:26:54.553 回答
5

PostgreSQL 还没有太多的 JSON 支持函数:我只能看到类似 的函数array_to_json,如果有相应的方法将原始 JSON 转换为数组,这可能很有用,然后您可以对其进行操作以添加额外的转换回 JSON 之前的元素。

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

当然,许多其他 PL 语言,如 Java、Python 或 Perl 可能同样擅长处理 JSON 数据,并且可能更容易安装在您的系统上。如果您设置了用户定义的函数,则可以在其中的每一个中编写它们。

于 2012-11-28T22:52:28.173 回答
4

9.5 版提供了带有 create_missing =TRUE 的jsonb_set函数。在任何其他情况下,使用以下 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)
于 2015-08-01T10:36:59.240 回答
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
  ;
于 2016-04-01T18:05:35.713 回答
1

Solution provided by Andrew Wolfe is good, but not compatible with postgres version < 9.4. And if you have a 9.4+ version, just use jsonb and || (concatenate) operator to add an element to json.

So, here is the 9.3 compatible version of json_extend_object:

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;
于 2020-03-10T19:11:31.893 回答