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

語言: CN / TW / HK

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部落格上。