在 Postgres 中向 JSON 对象添加元素

Posted

技术标签:

【中文标题】在 Postgres 中向 JSON 对象添加元素【英文标题】:Add element to JSON object in Postgres 【发布时间】:2012-11-16 22:26:24 【问题描述】:

我在数据库(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 中是否有一种简单的方法可以做到这一点?

【问题讨论】:

尝试阅读 ***.com/questions/10560394/… 。它可能会帮助你。 可能属于数据库管理员组 【参考方案1】:

如果升级到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>

【讨论】:

【参考方案2】:

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

示例:

原产地:

在表中a

标识 |信息

1 | "aa":"bb"

2 | "aa":"cc"

执行后:

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

生成:

标识 |信息

1 | "aa":"bb","id":1

2 | "aa":"cc","id":2

something_else:

    使用-‘key’删除jsonb中的元素 如果两个 jsonb 具有相同的 key,merge 将替换 origin 一个

【讨论】:

【参考方案3】:

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

【讨论】:

即使阁下'有同样的问题',那我们还有什么机会呢?哈哈【参考方案4】:

PostgreSQL 还没有太多的 JSON 支持函数:我只能看到像 array_to_json 这样的函数,如果有相应的方法将原始 JSON 转换为数组,这可能会很有用,你可以然后在转换回 JSON 之前进行操作以添加该附加元素。

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

http://code.google.com/p/plv8js/wiki/PLV8

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

【讨论】:

显然不是我想要的答案,但仍然令人愉快。谢谢。【参考方案5】:

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)

【讨论】:

感谢您的回答。 PostgreSQL 9.5 在 2 年前对我不可用。从那时起,我们开始使用 postgres 提供的 JSON 数据类型,并使用 php 进行编码/解码。当 JSON 只是数据库中的一个字符串时,它让事情变得更加困难。【参考方案6】:

我确实遇到了这个问题。这个解决方案是相当“纯”的对象操作,我更喜欢 '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
  ;

【讨论】:

如何添加到文档的开头? 将 'newvals' 子查询和 UNION 放在 'to_rows' 子查询的 'select json_val' 分支之前,而不是之后。【参考方案7】:

Andrew Wolfe 提供的解决方案很好,但与

所以,这里是 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;

【讨论】:

以上是关于在 Postgres 中向 JSON 对象添加元素的主要内容,如果未能解决你的问题,请参考以下文章

更改(映射)JSON列表形状 - 在TypeScript中向对象添加标记

在Java中向对象添加多个元素

在 AngularJS 中向 Json 数组添加函数

在单个 JSON Patch 操作中向数组添加多个值?

如何在 ngfor 中向元素添加 id 以及在 ngfor 中条件创建元素

如何在 Django 中向模型添加临时字段?