浏览Postgres 9.4数据类型JSONB的文档时,我并不清楚如何对JSONB列进行更新。

JSONB类型和函数的文档:

http://www.postgresql.org/docs/9.4/static/functions-json.html http://www.postgresql.org/docs/9.4/static/datatype-json.html

作为一个例子,我有这样一个基本的表结构:

CREATE TABLE test(id serial, data jsonb);

插入很容易,比如:

INSERT INTO test(data) values ('{"name": "my-name", "tags": ["tag1", "tag2"]}');

现在,我该如何更新“数据”列呢?这是无效的语法:

UPDATE test SET data->'name' = 'my-other-name' WHERE id = 1;

这是否被记录在我遗漏的某个地方?谢谢。


当前回答

对于那些遇到这个问题并想要快速修复的人(并且被困在9.4.5或更早的版本),这里有一个潜在的解决方案:

创建测试表

CREATE TABLE test(id serial, data jsonb);
INSERT INTO test(data) values ('{"name": "my-name", "tags": ["tag1", "tag2"]}');

更新语句更改jsonb值

UPDATE test 
SET data = replace(data::TEXT,': "my-name"',': "my-other-name"')::jsonb 
WHERE id = 1;

最终,接受的答案是正确的,因为你不能修改jsonb对象的单个部分(在9.4.5或更早的版本中);但是,您可以将jsonb列强制转换为字符串(::TEXT),然后操作字符串并强制转换回jsonb表单(::jsonb)。

这里有两个重要的警告

这将替换json中所有等于“my-name”的值(在这种情况下,您有多个具有相同值的对象) 如果您使用的是9.5,这就没有jsonb_set那么高效了

其他回答

这个问题是在postgres 9.4中提出的, 然而,新来的观众应该知道,在postgres 9.5中, 数据库本身支持对JSONB字段的创建/更新/删除操作,不需要扩展功能。

参见:JSONB修改操作符和函数

对于那些遇到这个问题并想要快速修复的人(并且被困在9.4.5或更早的版本),这里有一个潜在的解决方案:

创建测试表

CREATE TABLE test(id serial, data jsonb);
INSERT INTO test(data) values ('{"name": "my-name", "tags": ["tag1", "tag2"]}');

更新语句更改jsonb值

UPDATE test 
SET data = replace(data::TEXT,': "my-name"',': "my-other-name"')::jsonb 
WHERE id = 1;

最终,接受的答案是正确的,因为你不能修改jsonb对象的单个部分(在9.4.5或更早的版本中);但是,您可以将jsonb列强制转换为字符串(::TEXT),然后操作字符串并强制转换回jsonb表单(::jsonb)。

这里有两个重要的警告

这将替换json中所有等于“my-name”的值(在这种情况下,您有多个具有相同值的对象) 如果您使用的是9.5,这就没有jsonb_set那么高效了

理想情况下,对于希望在关系数据库中操作的结构化常规数据,不要使用JSON文档。请使用规范化的关系设计。

JSON主要用于存储RDBMS中不需要操作的整个文档。相关:

带索引的JSONB vs. hstore

在Postgres中更新一行总是会写入整行的新版本。这就是Postgres的MVCC模型的基本原理。从性能的角度来看,更改JSON对象中的单个数据还是全部数据几乎无关紧要:必须写入该行的新版本。

因此手册中的建议是:

JSON data is subject to the same concurrency-control considerations as any other data type when stored in a table. Although storing large documents is practicable, keep in mind that any update acquires a row-level lock on the whole row. Consider limiting JSON documents to a manageable size in order to decrease lock contention among updating transactions. Ideally, JSON documents should each represent an atomic datum that business rules dictate cannot reasonably be further subdivided into smaller datums that could be modified independently.

其要点是:要修改JSON对象中的任何内容,必须将修改后的对象分配给列。Postgres除了提供存储功能外,还提供了有限的方法来构建和操作json数据。自版本9.2以来,每个新版本的工具库都有了大幅增长。但基本原则仍然存在:你总是必须将一个完整的修改后的对象分配给列,并且Postgres总是为任何更新编写一个新的行版本。

使用Postgres 9.3或更高版本工具的一些技巧:

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

这个答案吸引的反对票和我在SO上的所有其他答案加起来一样多。人们似乎不喜欢这个想法:规范化设计对于规则数据更优越。Craig Ringer的这篇精彩的博客文章详细解释了这一点:

PostgreSQL反模式:不必要的json/hstore动态列

Laurenz Albe(与Craig和我一样是Postgres的官方贡献者)的另一篇博文:

PostgreSQL中的JSON:如何正确使用它

更新整个专栏对我来说很有效:

UPDATE test SET data='{"name": "my-other-name", "tags": ["tag1", "tag2"]}' where id=1;

可能: 更新test SET data = ' my-other-name '::json WHERE id = 1;

它适用于我的案例,其中data是json类型