在PostgreSQL v14中,JSON有什么新功能?

PostgreSQL v14最近发布了一些重大改进。其中一些改进包括增强了重载工作的性能,改进了对分布式工作负载的支持,以及安全方面的改进。

最激动人心的发布之一是对JSON的支持增强,这将是本篇博文的重点。

在我们深入研究这些改进之前,让我们好好了解一下JSON在PostgreSQL中的使用情况。这将有助于我们更好地理解这些改进。

PostgreSQL中JSON的简要历史

JSON是在Postgres的v9.2版本中首次被引入。虽然这是一个非常令人兴奋的发展,但它的实现并不完美。Postgres基本上验证了要存储的JSON是有效的JSON,并将其存储为一个文本字符串。

一个重大的改进是JSONB类型,它在9.4版本中发布。这通常被称为 "更好的JSON",原因很简单。JSONB以分解的二进制格式存储,这在存储时增加了一点转换开销,但在操作和查询JSON时非常有效。JSONB还支持对数据进行索引。大多数人喜欢在Postgres中使用JSONB而不是JSON。

在Postgres v12中,加入了JSONPath来提高查询JSON数据的效率。

这就把我们带到了现在。现在让我们考虑一下v14对JSON的改进。

v14的JSON便利性

Postgres v14允许你以传统的方式访问和操作JSON数据。让我们用一些例子来解释这个问题。

假设我们有一个博客文章表,其数据列以JSON格式存储。在这篇文章中,我们将在所有的例子中使用JSONB类型。

CREATE TABLE blogs (
  id serial,
  data JSONB
)

复制代码

我们还在其中插入一些测试值。

INSERT INTO 
  blogs (data)
VALUES 
 ('{"title": "blog one", "author": {"first_name": "Ada", "last_name": "Love"}}' ),
 ('{"title": "blog two", "author": {"first_name": "Star", "last_name": "Work"}}' );

复制代码

这将导致以下表格的出现。

SELECT *
 FROM blogs;

 id |                                     data                                     
----+------------------------------------------------------------------------------
  1 | {"title": "blog one", "author": {"last_name": "Love", "first_name": "Ada"}}
  2 | {"title": "blog two", "author": {"last_name": "Work", "first_name": "Star"}}
(2 rows)

复制代码

让我们看看v14的改进。

使用下标访问JSON数据

在Postgres 13和更早的版本中,如果你想找到所有作者的名字是 "Ada "的博客的标题,你会做以下工作。

SELECT data -> 'title' as title
FROM blogs 
WHERE data -> 'author' ->> 'first_name' = 'Ada' ;


   title    
------------
 "blog one"
(1 row)

复制代码

注意我们用来获取这些数据的操作符。

  • -> 是用来获取从零开始索引的JSON数组元素或JSON对象字段的键。
  • ->> 用来获取JSON数组元素或JSON对象字段的文本。

虽然这很有效,但记住这种语法并不是最简单的。这是因为该语法与访问JSON数据的传统方式不同。如果我们可以像我们习惯的那样使用下标来访问Postgres中存储的JSON数据呢?这就是Postgres v14带给我们的东西。

让我们尝试重新获取上面得到的数据,但这次是用Postgres v14的方式,使用子标。

SELECT data['title'] as title
FROM blogs 
WHERE data['author']['first_name'] = '"Ada"';

   title    
------------
 "blog one"
(1 row)

复制代码

注意,当用下标做比较时,你必须使用一个JSON字符串。

使用下标更新JSON

使用下标更新存储在Postgres中的JSON数据也很容易。在v13和更早的版本中,为了更新JSON,我们需要使用具有以下签名的jsonb_set 函数。

 jsonb_set (target jsonb, path text[], new_value jsonb [, create_if_missing boolean ])

复制代码

在这段代码中。
-target 是要更新的JSONB列
-path 表示你要更新的JSON键
-new_value 是要更新的项目的新值
-create_if_missing 是一个选项参数,指定如果路径指定的键不存在,是否应该创建键/值

现在,让我们用这个函数来更新上面例子中的数据列。例如,如果我们想用id 1 ,更新博客作者的姓,我们这样做。

UPDATE blogs
SET data = jsonb_set(data, '{author, last_name}', '"Sarah"', false)
WHERE id = 1;

复制代码

这将导致。

SELECT * FROM blogs;

 id |                                     data                                     
----+------------------------------------------------------------------------------
  2 | {"title": "blog two", "author": {"last_name": "Work", "first_name": "Star"}}
  1 | {"title": "blog one", "author": {"last_name": "Sarah", "first_name": "Ada"}}
(2 rows)

复制代码

在Postgres v14中,我们不需要使用jsonb_set 函数来更新JSONB数据。我们可以这样做。

UPDATE blogs                                                                       SET data['author']['first_name'] = '"Sarah"'                                       WHERE id = 2; 
//id is different in this case it updates a different row

复制代码

这将导致。

select * from blogs;                                                                
id  |                                  data                                      
----+---------------------------------------------------------------------------------
  1 | {"title": "blog one", "author": {"last_name": "Sarah", "first_name": "Ada"}}
  2 | {"title": "blog two", "author": {"last_name": "Work", "first_name": "Sarah"}}
(2 rows)

复制代码

第二行被更新。

使用下标更新JSON时需要注意的重要事项

通过下标使用JSON赋值处理一些边缘情况与jsonb_set 不同。让我们考虑其中的一些。

  • 如果被更新的JSON键的值是null ,通过下标的赋值将像键的值是一个空对象或数组一样。

所以在我们上面的例子中,如果我们试图用标签来更新一行,而这一标签并不存在于下面的任何一行中。

UPDATE blogs SET
data['tags'] =' ["postgresql"] '
WHERE id = 1;

复制代码

我们会得到这样的结果。

SELECT *
FROM blogs
WHERE id = 1;
  id | data ----+-----------------------------------------------------------------------------------------------------
  1 | {"tags": ["postgresql"], "title": "blog one", "author": {"last
复制代码

tags 始终被添加到该行。没有任何选项可以阻止它添加一个不存在的列,比如jsonb_set create_optional 参数。

  • 如果为一个数组指定了一个索引,而数组包含的元素太少,null ,直到达到索引为止。

因此,如果我们试图更新我们在前面的例子中添加的tags字段,其索引超过了数组的当前长度,像这样。

UPDATE blogs                                     SET
data['tags'][4] =' "javascript" '              WHERE
id = 1;
复制代码

我们会得到这样的结果。

SELECT * 
FROM blogs 
WHERE id = 1;

 id |                                    data         
----+-------------------------------------------------------------------------------------------------------------------------------------
  1 | {"tags": ["postgresql", null, null, null, "javascript"], "title": "blog one", "author": {"last_name": "Love", "first_name": "Ada"}}
(1 row)

复制代码

注意,null ,直到达到指定的索引为止。

  • 如果一个JSON值被分配给一个不存在的下标路径,而最后一个要被遍历的现有元素是一个对象或数组,嵌套的数组或对象将被创建。然而,就像上面的例子一样,null ,直到达到指定的索引,创建的对象或数组才会被放置

因此,在我们的例子中,如果我们做了以下工作。

UPDATE blogs
SET data['otherdata'][3]['address'] =' "New York" '                              
WHERE id = 2;

复制代码

我们得到以下结果。

 id |                data                                                         ----+--------------------------------------------------------------------------------------------------------------------------------------
  2 | {"title": "blog two", "author": {"last_name": "Work", "first_name": "Star"}, "otherdata": [null, null, null, {"address": "New York"}]}
(1 row)

复制代码

你可以看到,对象被创建了。然而,null ,直到达到索引为止。

总结

看到这些年来JSON支持在Postgres中得到了巨大的改善,这真的很令人激动。在这篇文章中,我们看到了在Postgres v14中加入的JSON下标是如何使访问和更新JSON变得容易的。我们还考虑了在使用下标时给JSON赋值的一些注意点。

这是否意味着下标完全取代了访问JSON数据的旧方式?不一定。例如,我们看到,在更新JSON值时,如果列不存在,就没有办法阻止它的创建。jsonb_set 函数给了我们这个选择。另外,在用下标访问你的JSON数据时,并不总是利用索引。然而,对于非复杂的查询,下标是可以使用的。

谁知道Postgres的新版本会带来什么改进?在使用下标时能更好地利用索引?通过点符号访问JSON?只有未来才能知道。

请查看关于JSON下标的官方文档以了解更多信息。

你也可以在这里了解Postgres v14的其他发布信息。

PostgreSQL v14中JSON的新功能出现在LogRocket博客上。

猜你喜欢

转载自juejin.im/post/7068173159257604126
今日推荐