本頁面說明使用 Spanner 時,如何處理 JSONB 資料類型。
JSONB 是 PostgreSQL 資料類型,用於在 Spanner PostgreSQL 方言中保存半結構化資料。JSONB 會以 JavaScript 物件標記法 (JSON) 格式保存資料,並遵循 RFC 7159 中所述的規格。
規格
Spanner JSONB 資料類型會儲存輸入文件的正規化表示法。這表示:
- 引號和空白字元不會保留。
- 不支援註解。含有註解的交易或查詢失敗。
- 物件鍵會先依鍵長度排序,然後依等效物件鍵長度按字母順序排序。如果物件鍵重複,系統只會保留最後一個。
- 原始類型 (
string、boolean、number和null) 會保留其類型和值。string類型值會完整保留。- 系統會保留結尾的零。
number類型值的輸出格式不使用科學記號。
JSONBnull值會視為 SQL 非NULL。例如:SELECT null::jsonb IS NULL; -- Returns true SELECT 'null'::jsonb IS NULL; -- Returns false SELECT '{"a":null}'::jsonb -> 'a' IS NULL; -- Returns false SELECT '{"a":null}'::jsonb -> 'b' IS NULL; -- Returns true SELECT '{"a":null}'::jsonb -> 'a'; -- Returns a JSONB 'null' SELECT '{"a":null}'::jsonb -> 'b'; -- Returns a SQL NULLJSONB 陣列元素順序會保留。
限制
Spanner JSONB 適用下列限制:
to_jsonb函式的引數只能來自 Spanner 支援的 PostgreSQL 資料類型。- 數字類型值在小數點前可有 4,932 位數,小數點後可有 16,383 位數。
- 正規化儲存格式的大小上限為 10 MB。
JSONB文件必須以 UTF-8 編碼。如果交易或查詢中的JSONB文件是以其他格式編碼,則會傳回錯誤。
比較和排序
您可以比較 JSONB 值是否相等和排序。您也可以在 GROUP BY 和 ORDER BY 子句中使用 JSONB 值。
比較不同類型的 JSONB 值時,適用下列關係:
Null (JSONB null) < String < Number < Boolean < Array < Object
比較相同類型的 JSONB 值時,適用下列規則:
- 物件:鍵/值組合較多的物件大於組合較少的物件。如果兩個物件的鍵/值組合數量相同,系統會按照「規格」中定義的鍵順序,逐一比較鍵/值組合 (先比較鍵,再比較值)。第一組不同的配對會決定順序。
- 陣列:元素較多的陣列大於元素較少的陣列。如果兩個陣列的元素數量相同,則會由左至右逐一比較索引。第一個不同的元素會決定陣列順序。
- 布林值:
true大於false。 - 數字:使用數值比較進行數學比較。
- 字串:使用標準字串比較規則,依字典順序比較。
JSONB 空值:所有
JSONBnull值都相等,且小於任何其他非空值 JSON 值。不過,有項極端情況適用:空頂層陣列
[]會視為小於 JSONB 空值。由於這項規則僅適用於頂層陣列,因此下列陳述式會傳回 true:'[]'::jsonb < 'null'::jsonb'null'::jsonb < '[[]]'::jsonb'[null]'::jsonb < '[[]]'::jsonb
建立含有 JSONB 資料欄的資料表
建立資料表時,您可以新增 JSONB 資料欄。
CREATE TABLE Venues (
VenueId BIGINT PRIMARY KEY,
VenueName VARCHAR(1024),
VenueAddress VARCHAR(1024),
VenueFeatures JSONB,
DateOpened TIMESTAMPTZ
);
以下是 VenueFeatures JSONB 物件範例:
{
"rating": 4.5,
"capacity":"1500",
"construction":"brick",
"tags": [
"multi-cuisine",
"open-seating",
"stage",
"public address system"
]
}
在現有資料表中新增及移除 JSONB 資料欄
您可以新增 JSONB 資料欄,並使用 ALTER 陳述式刪除該資料欄,如下所示:
ALTER TABLE Venues ADD COLUMN VenueDetails JSONB;
ALTER TABLE Venues DROP COLUMN VenueDetails;
下列範例說明如何使用 Spanner 用戶端程式庫,將名為 VenueDetails 的 JSONB 資料欄新增至 Venues 資料表。
C++
C#
Go
Java
Node.js
PHP
Python
小茹
修改 JSONB 資料
您可以像修改其他資料欄一樣,修改 JSONB 資料欄。
範例如下:
UPDATE Venues SET VenueFeatures = '{"rating": 4.5, "tags":["multi-cuisine", "open-seating"] }'
WHERE VenueId = 1;
以下範例說明如何使用 Spanner 用戶端程式庫更新 JSONB 資料。
C++
如要瞭解如何安裝及使用 Spanner 的用戶端程式庫,請參閱「Spanner 用戶端程式庫」。
如要向 Spanner 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
C#
如要瞭解如何安裝及使用 Spanner 的用戶端程式庫,請參閱「Spanner 用戶端程式庫」。
如要向 Spanner 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
Go
如要瞭解如何安裝及使用 Spanner 的用戶端程式庫,請參閱「Spanner 用戶端程式庫」。
如要向 Spanner 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
Java
如要瞭解如何安裝及使用 Spanner 的用戶端程式庫,請參閱「Spanner 用戶端程式庫」。
如要向 Spanner 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
Node.js
如要瞭解如何安裝及使用 Spanner 的用戶端程式庫,請參閱「Spanner 用戶端程式庫」。
如要向 Spanner 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
PHP
如要瞭解如何安裝及使用 Spanner 的用戶端程式庫,請參閱「Spanner 用戶端程式庫」。
如要向 Spanner 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
Python
如要瞭解如何安裝及使用 Spanner 的用戶端程式庫,請參閱「Spanner 用戶端程式庫」。
如要向 Spanner 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
Ruby
如要瞭解如何安裝及使用 Spanner 的用戶端程式庫,請參閱「Spanner 用戶端程式庫」。
如要向 Spanner 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
建立 JSON 資料索引
您可以搭配使用 JSONB 資料與次要索引和搜尋索引,加快查詢 JSONB 資料的速度。Spanner 不支援使用 JSONB 類型資料欄做為次要索引中的索引鍵。
使用次要索引
如要篩選 JSONB 文件中的純量值,次要索引就非常實用。如要搭配 JSONB 使用次要索引,請建立產生的資料欄,擷取相關純量資料,並轉換為適當的 SQL 資料類型。接著,您可以根據這個產生的資料欄建立次要索引。索引會加快對生成資料欄執行的合格查詢。
在以下範例中,您會建立 VenuesByCapacity 索引,資料庫會使用該索引尋找容納人數大於 1000 的場地。Spanner 不會檢查每個資料列,而是使用索引找出相關資料列,進而提升查詢效能,尤其是大型資料表。
ALTER TABLE Venues (
ADD COLUMN VenueCapacity BIGINT GENERATED ALWAYS AS ((VenueFeatures->>'capacity')::BIGINT) VIRTUAL,
DateOpened TIMESTAMPTZ
);
CREATE INDEX VenuesByCapacity ON Venues(VenueCapacity);
SELECT VenueName
FROM Venues
WHERE VenueCapacity > 1000;
使用搜尋索引
查詢動態或多樣的 JSONB 文件時,搜尋索引非常實用。與次要索引不同,您可以針對儲存在 JSONB 資料欄中的任何 JSONB 文件建立搜尋索引。搜尋索引會自動適應 JSON 文件、不同資料列和時間的變化。
在以下範例中,您會建立 VenuesByVenueDetails 搜尋索引,資料庫會使用該索引尋找具有特定詳細資料 (例如大小和營業時間) 的場地。Spanner 不會檢查每個資料列,而是使用索引找出相關資料列,進而提升查詢效能,尤其是大型資料表。
ALTER TABLE Venues
ADD COLUMN VenueDetails_Tokens spanner.tokenlist
GENERATED ALWAYS AS (spanner.tokenize_jsonb(VenueDetails)) VIRTUAL HIDDEN;
CREATE SEARCH INDEX VenuesByVenueDetails
ON Venues (VenueDetails_Tokens);
SELECT VenueName
FROM Venues
WHERE VenueDetails @> '{"labels": ["large"], "open": {"Friday": true}}'::jsonb;
SELECT VenueName
FROM Venues
WHERE VenueDetails->'open'->'Friday' = 'true'::jsonb
AND VenueDetails->'type' IN ('"stadium"'::jsonb, '"arena"'::jsonb);
詳情請參閱「JSON 搜尋索引」。
查詢 JSONB 資料
您可以根據基礎欄位的值查詢 JSONB 欄。以下範例從 Venues 擷取 VenueId 和 VenueName,其中 VenueFeatures 的 rating 值大於 3.5。
SELECT VenueId, VenueName
FROM Venues
WHERE (VenueFeatures->>'rating')::FLOAT8 > 3.5;
以下範例說明如何使用 Spanner 用戶端程式庫查詢 JSONB 資料。
C++
如要瞭解如何安裝及使用 Spanner 的用戶端程式庫,請參閱「Spanner 用戶端程式庫」。
如要向 Spanner 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
C#
如要瞭解如何安裝及使用 Spanner 的用戶端程式庫,請參閱「Spanner 用戶端程式庫」。
如要向 Spanner 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
Go
如要瞭解如何安裝及使用 Spanner 的用戶端程式庫,請參閱「Spanner 用戶端程式庫」。
如要向 Spanner 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
Java
如要瞭解如何安裝及使用 Spanner 的用戶端程式庫,請參閱「Spanner 用戶端程式庫」。
如要向 Spanner 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
Node.js
如要瞭解如何安裝及使用 Spanner 的用戶端程式庫,請參閱「Spanner 用戶端程式庫」。
如要向 Spanner 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
PHP
如要瞭解如何安裝及使用 Spanner 的用戶端程式庫,請參閱「Spanner 用戶端程式庫」。
如要向 Spanner 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
Python
如要瞭解如何安裝及使用 Spanner 的用戶端程式庫,請參閱「Spanner 用戶端程式庫」。
如要向 Spanner 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
Ruby
如要瞭解如何安裝及使用 Spanner 的用戶端程式庫,請參閱「Spanner 用戶端程式庫」。
如要向 Spanner 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
不支援的 PostgreSQL JSONB 功能
Spanner JSONB 不支援下列開放原始碼 PostgreSQL JSONB 功能:
- PrimaryKey 和 ForeignKey
- 建立索引,包括 GIN 索引。您可以改用 Spanner 搜尋索引,加快與 GIN 索引相同的 JSONB 作業。詳情請參閱「建立 JSON 資料索引」。
- 將
JSONB資料欄變更為任何其他資料類型,或從任何其他資料類型變更為 資料欄 - 在採用 PostgreSQL 有線通訊協定的工具中,使用參數化查詢搭配無類型 JSONB 參數
在查詢引擎中使用強制轉型。與開放原始碼 PostgreSQL 不同,系統不支援從
JSONB隱含強制轉型為文字。您必須使用JSONB類型的明確轉換,才能比對函式簽章。例如:SELECT concat('abc'::text, '{"key1":1}'::jsonb); -- Returns error SELECT concat('abc'::text, CAST('{"key1":1}'::jsonb AS TEXT)); -- This works SELECT 3 + CAST('5'::jsonb AS INTEGER); -- This works