如何修改新的PostgreSQL JSON数据类型中的字段?

使用postgresql 9.3我可以选择JSON数据类型的特定字段,但是如何使用UPDATE修改它们?我找不到任何这样的例子在postgresql文档,或在任何地方在线。我试过明显:
postgres=# create table test (data json);
CREATE TABLE
postgres=# insert into test (data) values ('{"a":1,"b":2}');
INSERT 0 1
postgres=# select data->'a' from test where data->>'b' = '2';
 ?column?
----------
 1
(1 row)
postgres=# update test set data->'a' = to_json(5) where data->>'b' = '2';
ERROR:  Syntax error at or near "->"
LINE 1: update test set data->'a' = to_json(5) where data->>'b' = '2...
更新: With PostgreSQL 9.5,在Postgresql本身中有一些jsonb操作的功能(但是没有一个用于json; cast需要操作json值)。

合并2个(或多个)JSON对象(或连接数组):

SELECT jsonb '{"a":1}' || jsonb '{"b":2}',-- will yield jsonb '{"a":1,"b":2}'
       jsonb '["a",1]' || jsonb '["b",2]'  -- will yield jsonb '["a",1,"b",2]'

因此,设置一个简单的密钥可以使用:

SELECT jsonb '{"a":1}' || jsonb_build_object('<key>','<value>')

其中< key>应为字符串,< value>可以是to_jsonb()接受的任何类型。

对于在JSON层次结构中深度设置值,可以使用jsonb_set()函数

SELECT jsonb_set('{"a":[null,{"b":[]}]}','{a,b,0}',jsonb '{"c":3}')
-- will yield jsonb '{"a":[null,{"b":[{"c":3}]}]}'

jsonb_set()的完整参数列表:

jsonb_set(target jsonb,path text[],new_value jsonb,create_missing boolean default true)

从JSON对象(或从数组)中删除键(或索引)可以使用 – 运算符完成:

SELECT jsonb '{"a":1,"b":2}' - 'a',-- will yield jsonb '{"b":2}'
       jsonb '["a",2]' - 1    -- will yield jsonb '["a",2]'

在JSON层次结构中从深层删除,可以使用# – 运算符:

SELECT '{"a":[null,{"b":[3.14]}]}' #- '{a,0}'
-- will yield jsonb '{"a":[null,{"b":[]}]}'

原始答案:这是可能的(没有plpython或plv8)在纯sql也(但需要9.3,将不能与9.2工作)

CREATE OR REPLACE FUNCTION "json_object_set_key"(
  "json"          json,"key_to_set"    TEXT,"value_to_set"  anyelement
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT concat('{',string_agg(to_json("key") || ':' || "value",','),'}')::json
  FROM (SELECT *
          FROM json_each("json")
         WHERE "key" <> "key_to_set"
         UNION ALL
        SELECT "key_to_set",to_json("value_to_set")) AS "fields"
$function$;

SQLFiddle

编辑:

一个版本,它设置多个键&值:

CREATE OR REPLACE FUNCTION "json_object_set_keys"(
  "json"          json,"keys_to_set"   TEXT[],"values_to_set" anyarray
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT concat('{','}')::json
  FROM (SELECT *
          FROM json_each("json")
         WHERE "key" <> ALL ("keys_to_set")
         UNION ALL
        SELECT disTINCT ON ("keys_to_set"["index"])
               "keys_to_set"["index"],CASE
                 WHEN "values_to_set"["index"] IS NULL THEN 'null'::json
                 ELSE to_json("values_to_set"["index"])
               END
          FROM generate_subscripts("keys_to_set",1) AS "keys"("index")
          JOIN generate_subscripts("values_to_set",1) AS "values"("index")
         USING ("index")) AS "fields"
$function$;

编辑2:作为@ErwinBrandstetter noted上面的这些功能一个所谓的UPSERT(更新一个字段,如果存在,插入如果它不存在)。这里是一个变体,其中只有UPDATE:

CREATE OR REPLACE FUNCTION "json_object_update_key"(
  "json"          json,"value_to_set"  anyelement
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT CASE
  WHEN ("json" -> "key_to_set") IS NULL THEN "json"
  ELSE (SELECT concat('{','}')
          FROM (SELECT *
                  FROM json_each("json")
                 WHERE "key" <> "key_to_set"
                 UNION ALL
                SELECT "key_to_set",to_json("value_to_set")) AS "fields")::json
END
$function$;

编辑3:这是递归变量,它可以设置(UPSERT)叶值(并使用来自此答案的第一个函数),位于键路径(其中键只能引用内部对象,不支持内部数组):

CREATE OR REPLACE FUNCTION "json_object_set_path"(
  "json"          json,"key_path"      TEXT[],"value_to_set"  anyelement
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT CASE COALESCE(array_length("key_path",1),0)
         WHEN 0 THEN to_json("value_to_set")
         WHEN 1 THEN "json_object_set_key"("json","key_path"[l],"value_to_set")
         ELSE "json_object_set_key"(
           "json","json_object_set_path"(
             COALESCE(NULLIF(("json" -> "key_path"[l])::text,'null'),'{}')::json,"key_path"[l+1:u],"value_to_set"
           )
         )
       END
  FROM array_lower("key_path",1) l,array_upper("key_path",1) u
$function$;

更新:功能现在紧凑。

相关文章

项目需要,有个数据需要导入,拿到手一开始以为是mysql,结果...
本文小编为大家详细介绍“怎么查看PostgreSQL数据库中所有表...
错误现象问题原因这是在远程连接时pg_hba.conf文件没有配置正...
因本地资源有限,在公共测试环境搭建了PGsql环境,从数据库本...
wamp 环境 这个提示就是说你的版本低于10了。 先打印ph...
psycopg2.OperationalError: SSL SYSCALL error: EOF detect...