在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的其他发布信息。
- 在C 中把字符串转换为整数的两种简单方法
- 如何在Flutter中实现任何UI
- Gatsby v4的新内容
- 创建一个Puppeteer微服务以部署到Google Cloud Functions
- 在Blazor中测试。一个完整的教程
- 在React中使用Plotly来构建动态图表
- 分页、加载更多按钮和无限滚动的指南
- 用新的Firebase v9.x Web SDK重构一个React应用
- 在使用地理定位API时,你需要知道什么?
- 在PostgreSQL v14中,JSON有什么新功能?
- 使用React的函数式编程的基础知识
- 使用Dart FFI访问Flutter中的本地库
- 使用视频播放器插件在Flutter中处理视频
- 改进过度约束的Rust库API
- 用Svelte建立一个PWA
- 用Flask和D3.js构建交互式图表
- 在Go中使用JSON。带例子的指南
- 一篇文章入门Unix中的AWK命令!
- C 哈希
- Dotfiles - 什么是Dotfile以及如何在Mac和Linux中创建它