W3Cschool
恭喜您成為首批注冊(cè)用戶(hù)
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
jsonb
包含和存在jsonb
索引
根據(jù)RFC 7159
中的說(shuō)明,JSON 數(shù)據(jù)類(lèi)型是用來(lái)存儲(chǔ) JSON(JavaScript Object Notation)
數(shù)據(jù)的。這種數(shù)據(jù)也可以被存儲(chǔ)為text
,但是 JSON 數(shù)據(jù)類(lèi)型的
優(yōu)勢(shì)在于能強(qiáng)制要求每個(gè)被存儲(chǔ)的值符合 JSON 規(guī)則。也有很多 JSON 相關(guān)的函
數(shù)和操作符可以用于存儲(chǔ)在這些數(shù)據(jù)類(lèi)型中的數(shù)據(jù),見(jiàn)
第 9.16 節(jié)。
PostgreSQL 提供存儲(chǔ)JSON數(shù)據(jù)的兩種類(lèi)型:json
和 jsonb
。
為了實(shí)現(xiàn)這些數(shù)據(jù)類(lèi)型高效的查詢(xún)機(jī)制, PostgreSQL還在第 8.14.6 節(jié)中提供了jsonpath
數(shù)據(jù)類(lèi)型描述。
json
和 jsonb
數(shù)據(jù)類(lèi)型接受幾乎完全相同的值集合作為輸入。
主要的實(shí)際區(qū)別之一是效率。json
數(shù)據(jù)類(lèi)型存儲(chǔ)輸入文本的精準(zhǔn)拷貝,處理函數(shù)必須在每
次執(zhí)行時(shí)必須重新解析該數(shù)據(jù)。而jsonb
數(shù)據(jù)被存儲(chǔ)在一種分解好的
二進(jìn)制格式中,它在輸入時(shí)要稍慢一些,因?yàn)樾枰龈郊拥霓D(zhuǎn)換。但是
jsonb
在處理時(shí)要快很多,因?yàn)椴恍枰馕觥?code class="type">jsonb也支
持索引,這也是一個(gè)令人矚目的優(yōu)勢(shì)。
由于json
類(lèi)型存儲(chǔ)的是輸入文本的準(zhǔn)確拷貝,其中可能會(huì)保留在語(yǔ)法
上不明顯的、存在于記號(hào)之間的空格,還有 JSON 對(duì)象內(nèi)部的鍵的順序。還有,
如果一個(gè)值中的 JSON 對(duì)象包含同一個(gè)鍵超過(guò)一次,所有的鍵/值對(duì)都會(huì)被保留(
處理函數(shù)會(huì)把最后的值當(dāng)作有效值)。相反,jsonb
不保留空格、不
保留對(duì)象鍵的順序并且不保留重復(fù)的對(duì)象鍵。如果在輸入中指定了重復(fù)的鍵,只有
最后一個(gè)值會(huì)被保留。
通常,除非有特別特殊的需要(例如遺留的對(duì)象鍵順序假設(shè)),大多數(shù)應(yīng)用應(yīng)該
更愿意把 JSON 數(shù)據(jù)存儲(chǔ)為jsonb
。
RFC 7159 指定 JSON 字符串應(yīng)以 UTF8 編碼。因此 JSON 類(lèi)型不可能?chē)?yán)格遵守 JSON 規(guī)范,除非數(shù)據(jù)庫(kù)編碼 是 UTF8。嘗試直接包括數(shù)據(jù)庫(kù)編碼中無(wú)法表示的字符將會(huì)失敗。反過(guò)來(lái),能 在數(shù)據(jù)庫(kù)編碼中表示但是不在 UTF8 中的字符是被允許的。
RFC 7159 允許 JSON 字符串包含\u
所標(biāo)記的 Unicode 轉(zhuǎn)義序列。在XXXX
json
類(lèi)型的輸入函數(shù)中,不管數(shù)據(jù)庫(kù)
編碼如何都允許 Unicode 轉(zhuǎn)義,并且只檢查語(yǔ)法正確性(即,跟在\u
后面的四個(gè)十六進(jìn)制位)。但是,jsonb
的輸入函數(shù)更加嚴(yán)格:它不允許對(duì)無(wú)法在數(shù)據(jù)庫(kù)
編碼中表示的字符進(jìn)行 Unicode 轉(zhuǎn)義。jsonb
類(lèi)型也拒絕\u0000
(因?yàn)? PostgreSQL的text
類(lèi)型無(wú)法表示
它),并且它堅(jiān)持使用 Unicode 代理對(duì)來(lái)標(biāo)記位于 Unicode 基本多語(yǔ)言平面之外
的字符是正確的。合法的 Unicode 轉(zhuǎn)義會(huì)被轉(zhuǎn)換成等價(jià)的單個(gè)字符進(jìn)
行存儲(chǔ),這包括把代理對(duì)折疊成一個(gè)單一字符。
很多第 9.16 節(jié)中描述的 JSON 處理函數(shù)將把 Unicode
轉(zhuǎn)義轉(zhuǎn)換成常規(guī)字符,并且將因此拋出和剛才所描述的同樣類(lèi)型的錯(cuò)誤(即使它們
的輸入是類(lèi)型json
而不是jsonb
)。json
的
輸入函數(shù)不做這些檢查是由來(lái)已久的,不過(guò)它確實(shí)允許將 JSON Unicode 轉(zhuǎn)義簡(jiǎn)單
的(不經(jīng)處理)存儲(chǔ)在一個(gè)不支持所表示字符的數(shù)據(jù)庫(kù)編碼中。
在把文本 JSON 輸入轉(zhuǎn)換成jsonb
時(shí),RFC 7159描述
的基本類(lèi)型會(huì)被有效地映射到原生的
PostgreSQL類(lèi)型(如
表 8.23中所示)。因此,在合法
jsonb
數(shù)據(jù)的組成上有一些次要額外約束,它們不適合
json
類(lèi)型和抽象意義上的 JSON,這些約束對(duì)應(yīng)于有關(guān)哪些東西不
能被底層數(shù)據(jù)類(lèi)型表示的限制。尤其是,jsonb
將拒絕位于
PostgreSQL numeric
數(shù)據(jù)類(lèi)型范
圍之外的數(shù)字,而json
則不會(huì)。這類(lèi)實(shí)現(xiàn)定義的限制是
RFC 7159 所允許的。不過(guò),實(shí)際上這類(lèi)問(wèn)題更可能發(fā)生在其他實(shí)
現(xiàn)中,因?yàn)榘?JSON 的number
基本類(lèi)型表示為 IEEE 754 雙精度浮點(diǎn)
是很常見(jiàn)的(這也是RFC 7159 明確期待和允許的)。當(dāng)在這類(lèi)系
統(tǒng)間使用 JSON 作為一種交換格式時(shí),應(yīng)該考慮丟失數(shù)字精度的風(fēng)險(xiǎn)。
相反地,如表中所述,有一些 JSON 基本類(lèi)型輸入格式上的次要限制并不適用于相 應(yīng)的PostgreSQL類(lèi)型。
表 8.23. JSON 基本類(lèi)型和相應(yīng)的PostgreSQL類(lèi)型
JSON 基本類(lèi)型 | PostgreSQL類(lèi)型 | 注釋 |
---|---|---|
string | text | \u0000 是不允許的,因?yàn)?Unicode 轉(zhuǎn)義表示數(shù)據(jù)庫(kù)編碼中不可用的字符 |
number | numeric | 不允許NaN 和 infinity 值 |
boolean | boolean | 只接受小寫(xiě)true 和false 拼寫(xiě) |
null | (無(wú)) | SQL NULL 是一個(gè)不同的概念 |
RFC 7159 中定義了 JSON 數(shù)據(jù)類(lèi)型的輸入/輸出語(yǔ)法。
下列都是合法的json
(或者jsonb
)表達(dá)式:
-- 簡(jiǎn)單標(biāo)量/基本值
-- 基本值可以是數(shù)字、帶引號(hào)的字符串、true、false或者null
SELECT '5'::json;
-- 有零個(gè)或者更多元素的數(shù)組(元素不需要為同一類(lèi)型)
SELECT '[1, 2, "foo", null]'::json;
-- 包含鍵值對(duì)的對(duì)象
-- 注意對(duì)象鍵必須總是帶引號(hào)的字符串
SELECT '{"bar": "baz", "balance": 7.77, "active": false}'::json;
-- 數(shù)組和對(duì)象可以被任意嵌套
SELECT '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}'::json;
如前所述,當(dāng)一個(gè) JSON 值被輸入并且接著不做任何附加處理就輸出時(shí),
json
會(huì)輸出和輸入完全相同的文本,而jsonb
則不會(huì)保留語(yǔ)義上沒(méi)有意義的細(xì)節(jié)(例如空格)。例如,注意下面的不同:
SELECT '{"bar": "baz", "balance": 7.77, "active":false}'::json;
json
-------------------------------------------------
{"bar": "baz", "balance": 7.77, "active":false}
(1 row)
SELECT '{"bar": "baz", "balance": 7.77, "active":false}'::jsonb;
jsonb
--------------------------------------------------
{"bar": "baz", "active": false, "balance": 7.77}
(1 row)
值得一提的一種語(yǔ)義上無(wú)意義的細(xì)節(jié)是,在jsonb
中數(shù)據(jù)會(huì)被按照底層
numeric
類(lèi)型的行為來(lái)打印。實(shí)際上,這意味著用E
記號(hào)
輸入的數(shù)字被打印出來(lái)時(shí)就不會(huì)有該記號(hào),例如:
SELECT '{"reading": 1.230e-5}'::json, '{"reading": 1.230e-5}'::jsonb;
json | jsonb
-----------------------+-------------------------
{"reading": 1.230e-5} | {"reading": 0.00001230}
(1 row)
不過(guò),如這個(gè)例子所示,jsonb
將會(huì)保留拖尾的小數(shù)點(diǎn)后的零,即便這
對(duì)于等值檢查等目的來(lái)說(shuō)是語(yǔ)義上無(wú)意義的。
對(duì)于可用于構(gòu)造和處理 JSON 值的內(nèi)置函數(shù)和運(yùn)算符的列表,參見(jiàn) 第 9.16 節(jié)。
將數(shù)據(jù)表示為 JSON 比傳統(tǒng)關(guān)系數(shù)據(jù)模型要靈活得多,在需求不固定時(shí) 這種優(yōu)勢(shì)更加令人感興趣。在同一個(gè)應(yīng)用里非常有可能有兩種方法共存 并且互補(bǔ)。不過(guò),即便是在要求最大靈活性的應(yīng)用中,我們還是推薦 JSON 文檔有固定的結(jié)構(gòu)。該結(jié)構(gòu)通常是非強(qiáng)制的(盡管可能會(huì)強(qiáng)制一 些業(yè)務(wù)規(guī)則),但是有一個(gè)可預(yù)測(cè)的結(jié)構(gòu)會(huì)使書(shū)寫(xiě)概括一個(gè)表中的 “文檔”(數(shù)據(jù))集合的查詢(xún)更容易。
當(dāng)被存儲(chǔ)在表中時(shí),JSON 數(shù)據(jù)也像其他數(shù)據(jù)類(lèi)型一樣服從相同的并發(fā) 控制考慮。盡管存儲(chǔ)大型文檔是可行的,但是要記住任何更新都在整行 上要求一個(gè)行級(jí)鎖。為了在更新事務(wù)之間減少鎖爭(zhēng)奪,可考慮把 JSON 文檔限制到一個(gè)可管理的尺寸。理想情況下,JSON 文檔應(yīng)該每個(gè)表示 一個(gè)原子數(shù)據(jù),業(yè)務(wù)規(guī)則命令不會(huì)進(jìn)一步把它們劃分成更小的可獨(dú)立修 改的數(shù)據(jù)。
jsonb
包含和存在
測(cè)試包含是jsonb
的一種重要能力。對(duì)
json
類(lèi)型沒(méi)有平行的功能集。包含測(cè)試會(huì)測(cè)試一個(gè)
jsonb
文檔是否被包含在另一個(gè)文檔中。除了特別注解
之外,這些例子都會(huì)返回真:
-- 簡(jiǎn)單的標(biāo)量/基本值只包含相同的值:
SELECT '"foo"'::jsonb @> '"foo"'::jsonb;
-- 右邊的數(shù)字被包含在左邊的數(shù)組中:
SELECT '[1, 2, 3]'::jsonb @> '[1, 3]'::jsonb;
-- 數(shù)組元素的順序沒(méi)有意義,因此這個(gè)例子也返回真:
SELECT '[1, 2, 3]'::jsonb @> '[3, 1]'::jsonb;
-- 重復(fù)的數(shù)組元素也沒(méi)有關(guān)系:
SELECT '[1, 2, 3]'::jsonb @> '[1, 2, 2]'::jsonb;
-- 右邊具有一個(gè)單一鍵值對(duì)的對(duì)象被包含在左邊的對(duì)象中:
SELECT '{"product": "PostgreSQL", "version": 9.4, "jsonb": true}'::jsonb @> '{"version": 9.4}'::jsonb;
-- 右邊的數(shù)組不會(huì)被認(rèn)為包含在左邊的數(shù)組中,
-- 即使其中嵌入了一個(gè)相似的數(shù)組:
SELECT '[1, 2, [1, 3]]'::jsonb @> '[1, 3]'::jsonb; -- 得到假
-- 但是如果同樣也有嵌套,包含就成立:
SELECT '[1, 2, [1, 3]]'::jsonb @> '[[1, 3]]'::jsonb;
-- 類(lèi)似的,這個(gè)例子也不會(huì)被認(rèn)為是包含:
SELECT '{"foo": {"bar": "baz"}}'::jsonb @> '{"bar": "baz"}'::jsonb; -- 得到假
-- 包含一個(gè)頂層鍵和一個(gè)空對(duì)象:
SELECT '{"foo": {"bar": "baz"}}'::jsonb @> '{"foo": {}}'::jsonb;
一般原則是被包含的對(duì)象必須在結(jié)構(gòu)和數(shù)據(jù)內(nèi)容上匹配包含對(duì)象,這種匹配 可以是從包含對(duì)象中丟棄了不匹配的數(shù)組元素或者對(duì)象鍵值對(duì)之后成立。但 是記住做包含匹配時(shí)數(shù)組元素的順序是沒(méi)有意義的,并且重復(fù)的數(shù)組元素實(shí) 際也只會(huì)考慮一次。
結(jié)構(gòu)必須匹配的一般原則有一種特殊情況,一個(gè)數(shù)組可以包含一個(gè)基本值:
-- 這個(gè)數(shù)組包含基本字符串值:
SELECT '["foo", "bar"]'::jsonb @> '"bar"'::jsonb;
-- 反之不然,下面的例子會(huì)報(bào)告“不包含”:
SELECT '"bar"'::jsonb @> '["bar"]'::jsonb; -- 得到假
jsonb
還有一個(gè)存在操作符,它是包含的一種
變體:它測(cè)試一個(gè)字符串(以一個(gè)text
值的形式給出)是否出
現(xiàn)在jsonb
值頂層的一個(gè)對(duì)象鍵或者數(shù)組元素中。除非特別注解,
下面這些例子返回真:
-- 字符串作為一個(gè)數(shù)組元素存在:
SELECT '["foo", "bar", "baz"]'::jsonb ? 'bar';
-- 字符串作為一個(gè)對(duì)象鍵存在:
SELECT '{"foo": "bar"}'::jsonb ? 'foo';
-- 不考慮對(duì)象值:
SELECT '{"foo": "bar"}'::jsonb ? 'bar'; -- 得到假
-- 和包含一樣,存在必須在頂層匹配:
SELECT '{"foo": {"bar": "baz"}}'::jsonb ? 'bar'; -- 得到假
-- 如果一個(gè)字符串匹配一個(gè)基本 JSON 字符串,它就被認(rèn)為存在:
SELECT '"foo"'::jsonb ? 'foo';
當(dāng)涉及很多鍵或元素時(shí),JSON 對(duì)象比數(shù)組更適合于做包含或存在測(cè)試, 因?yàn)樗鼈儾幌駭?shù)組,進(jìn)行搜索時(shí)會(huì)進(jìn)行內(nèi)部?jī)?yōu)化,并且不需要被線性搜索。
由于 JSON 的包含是嵌套的,因此一個(gè)恰當(dāng)?shù)牟樵?xún)可以跳過(guò)對(duì)子對(duì)象的顯式選擇。
例如,假設(shè)我們?cè)陧攲佑幸粋€(gè)doc
列包含著對(duì)象,大部分對(duì)象
包含著tags
域,其中有子對(duì)象的數(shù)組。這個(gè)查詢(xún)會(huì)找到其中出現(xiàn)了
同時(shí)包含"term":"paris"
和"term":"food"
的子對(duì)象
的項(xiàng),而忽略任何位于tags
數(shù)組之外的這類(lèi)鍵:
SELECT doc->'site_name' FROM websites
WHERE doc @> '{"tags":[{"term":"paris"}, {"term":"food"}]}';
可以用下面的查詢(xún)完成同樣的事情:
SELECT doc->'site_name' FROM websites
WHERE doc->'tags' @> '[{"term":"paris"}, {"term":"food"}]';
但是后一種方法靈活性較差,并且常常也效率更低。
在另一方面,JSON 的存在操作符不是嵌套的:它將只在 JSON 值的頂層 查找指定的鍵或數(shù)組元素。
第 9.16 節(jié)中記錄了多個(gè)包含和存在操作符,以及 所有其他 JSON 操作符和函數(shù)。
jsonb
索引
GIN 索引可以被用來(lái)有效地搜索在大量jsonb
文檔(數(shù)據(jù))中出現(xiàn)
的鍵或者鍵值對(duì)。提供了兩種 GIN “操作符類(lèi)”,它們?cè)谛阅芎挽`活
性方面做出了不同的平衡。
jsonb
的默認(rèn) GIN 操作符類(lèi)支持使用@>
、
?
、?&
以及?|
操作符的查詢(xún)(這些
操作符實(shí)現(xiàn)的詳細(xì)語(yǔ)義請(qǐng)見(jiàn)表 9.45)。
使用這種操作符類(lèi)創(chuàng)建一個(gè)索引的例子:
CREATE INDEX idxgin ON api USING gin (jdoc);
非默認(rèn)的 GIN 操作符類(lèi)jsonb_path_ops
只支持索引
@>
操作符。使用這種操作符類(lèi)創(chuàng)建一個(gè)索引的例子:
CREATE INDEX idxginp ON api USING gin (jdoc jsonb_path_ops);
考慮這樣一個(gè)例子:一個(gè)表存儲(chǔ)了從一個(gè)第三方 Web 服務(wù)檢索到的 JSON 文檔,并且有一個(gè)模式定義。一個(gè)典型的文檔:
{
"guid": "9c36adc1-7fb5-4d5b-83b4-90356a46061a",
"name": "Angela Barton",
"is_active": true,
"company": "Magnafone",
"address": "178 Howard Place, Gulf, Washington, 702",
"registered": "2009-11-07T08:53:22 +08:00",
"latitude": 19.793713,
"longitude": 86.513373,
"tags": [
"enim",
"aliquip",
"qui"
]
}
我們把這些文檔存儲(chǔ)在一個(gè)名為api
的表的名為
jdoc
的jsonb
列中。如果在這個(gè)列上創(chuàng)建一個(gè)
GIN 索引,下面這樣的查詢(xún)就能利用該索引:
-- 尋找鍵 "company" 有值 "Magnafone" 的文檔
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @> '{"company": "Magnafone"}';
不過(guò),該索引不能被用于下面這樣的查詢(xún),因?yàn)楸M管操作符?
是可索引的,但它不能直接被應(yīng)用于被索引列jdoc
:
-- 尋找這樣的文檔:其中的鍵 "tags" 包含鍵或數(shù)組元素 "qui"
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc -> 'tags' ? 'qui';
但是,通過(guò)適當(dāng)?shù)厥褂帽磉_(dá)式索引,上述查詢(xún)也能使用一個(gè)索引。
如果對(duì)"tags"
鍵中的特定項(xiàng)的查詢(xún)很常見(jiàn),可能值得
定義一個(gè)這樣的索引:
CREATE INDEX idxgintags ON api USING gin ((jdoc -> 'tags'));
現(xiàn)在,WHERE
子句 jdoc -> 'tags' ? 'qui'
將被識(shí)別為可索引操作符?
在索引表達(dá)式jdoc -> 'tags'
上的應(yīng)用(更多有關(guān)表達(dá)式索引的信息可見(jiàn)第 11.7 節(jié))。
此外, GIN 索引支持 @@
和 @?
運(yùn)算符, 以執(zhí)行 jsonpath
匹配。
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @@ '$.tags[*] == "qui"';
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @? '$.tags[*] ? (@ == "qui")';
GIN 索引從jsonpath
中提取如下格式的語(yǔ)句: accessors_chain
= const
。
存取器鏈可能由.key
[*]
, 和 [
存取器組成。
index
]jsonb_ops
此外還支持 .*
和 .**
存取器。
另一種查詢(xún)的方法是利用包含,例如:
-- 尋找這樣的文檔:其中鍵 "tags" 包含數(shù)組元素 "qui"
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @> '{"tags": ["qui"]}';
jdoc
列上的一個(gè)簡(jiǎn)單 GIN 索引就能支持這個(gè)查詢(xún)。
但是注意這樣一個(gè)索引將會(huì)存儲(chǔ)jdoc
列中每一個(gè)鍵
和值的拷貝,然而前一個(gè)例子的表達(dá)式索引只存儲(chǔ)tags
鍵下找到的數(shù)據(jù)。雖然簡(jiǎn)單索引的方法更加靈活(因?yàn)樗С钟嘘P(guān)任
意鍵的查詢(xún)),定向的表達(dá)式索引更小并且搜索速度比簡(jiǎn)單索引更快。
盡管jsonb_path_ops
操作符類(lèi)只支持用
@>
,@@
和@?
操作符的查詢(xún),但它比起默認(rèn)的操作符類(lèi)
jsonb_ops
有更客觀的性能優(yōu)勢(shì)。一個(gè)
jsonb_path_ops
索引通常也比一個(gè)相同數(shù)據(jù)上的
jsonb_ops
要小得多,并且搜索的專(zhuān)一性更好,特
別是當(dāng)查詢(xún)包含頻繁出現(xiàn)在該數(shù)據(jù)中的鍵時(shí)。因此,其上的搜索操作
通常比使用默認(rèn)操作符類(lèi)的搜索表現(xiàn)更好。
jsonb_ops
和jsonb_path_ops
GIN 索引之間的技術(shù)區(qū)別是前者為數(shù)據(jù)中的每一個(gè)鍵和值創(chuàng)建獨(dú)立的索引項(xiàng),
而后者值為該數(shù)據(jù)中的每個(gè)值創(chuàng)建索引項(xiàng)。
基本上,每一個(gè)jsonb_path_ops
索引項(xiàng)是其所對(duì)應(yīng)的值和
鍵的哈希。例如要索引{"foo": {"bar": "baz"}}
,將創(chuàng)建一個(gè)
單一的索引項(xiàng),它把所有三個(gè)foo
、bar
、
和baz
合并到哈希值中。因此一個(gè)查找這個(gè)結(jié)構(gòu)的包含查詢(xún)可能
導(dǎo)致極度詳細(xì)的索引搜索。但是根本沒(méi)有辦法找到foo
是否作為
一個(gè)鍵出現(xiàn)。在另一方面,一個(gè)jsonb_ops
會(huì)創(chuàng)建三個(gè)索引
項(xiàng)分別表示foo
、bar
和baz
。那么要
做同樣的包含查詢(xún),它將會(huì)查找包含所有三個(gè)項(xiàng)的行。雖然 GIN 索引能夠相當(dāng)
有效地執(zhí)行這種 AND 搜索,它仍然不如等效的
jsonb_path_ops
搜索那樣詳細(xì)和快速(特別是如果有大量
行包含三個(gè)索引項(xiàng)中的任意一個(gè)時(shí))。
jsonb_path_ops
方法的一個(gè)不足是它不會(huì)為不包含任何值
的 JSON 結(jié)構(gòu)創(chuàng)建索引項(xiàng),例如{"a": {}}
。如果需要搜索包
含這樣一種結(jié)構(gòu)的文檔,它將要求一次全索引掃描,那就非常慢。
因此jsonb_path_ops
不適合經(jīng)常執(zhí)行這類(lèi)搜索的應(yīng)用。
jsonb
也支持btree
和hash
索引。
這通常值用于檢查完整 JSON 文檔等值非常重要的場(chǎng)合。jsonb
數(shù)據(jù)的btree
順序很少有人關(guān)系,但是為了完整性其順序是:
對(duì)象
> 數(shù)組
> 布爾
> 數(shù)字
> 字符串
> 空值
帶有 n 對(duì)的對(duì)象
> 帶有 n - 1 對(duì)的對(duì)象
帶有 n 個(gè)元素的數(shù)組
> 帶有 n - 1 個(gè)元素的數(shù)組
具有相同數(shù)量對(duì)的對(duì)象這樣比較:
key-1
, value-1
, key-2
...
注意對(duì)象鍵被按照它們的存儲(chǔ)順序進(jìn)行比較,特別是由于較短的鍵被存儲(chǔ)在 較長(zhǎng)的鍵之前,這可能導(dǎo)致結(jié)果不直觀,例如:
{ "aa": 1, "c": 1} > {"b": 1, "d": 1}
相似地,具有相同元素?cái)?shù)量的數(shù)組按照以下順序比較:
element-1
, element-2
...
基本 JSON 值的比較會(huì)使用低層PostgreSQL 數(shù)據(jù)類(lèi)型相同的比較規(guī)則進(jìn)行。字符串的比較會(huì)使用默認(rèn)的數(shù)據(jù)庫(kù)排序規(guī)則。
有一些附加的擴(kuò)展可以為不同的過(guò)程語(yǔ)言實(shí)現(xiàn)jsonb
類(lèi)型的轉(zhuǎn)換。
PL/Perl的擴(kuò)展被稱(chēng)作jsonb_plperl
和jsonb_plperlu
。如果使用它們,jsonb
值會(huì)視情況被映射為Perl的數(shù)組、哈希和標(biāo)量。
PL/Python的擴(kuò)展被稱(chēng)作jsonb_plpythonu
、jsonb_plpython2u
和jsonb_plpython3u
(PL/Python命名習(xí)慣請(qǐng)見(jiàn)第 45.1 節(jié))。如果使用它們,jsonb
值會(huì)視情況被映射為Python的詞典、列表和標(biāo)量。
在這些擴(kuò)展中,jsonb_plperl
被認(rèn)為是“trusted”,
也就是說(shuō),它可以由對(duì)當(dāng)前數(shù)據(jù)庫(kù)具有CREATE
權(quán)限的非超級(jí)用戶(hù)安裝。
其余的需要超級(jí)用戶(hù)權(quán)限才能安裝。
在PostgreSQL中,jsonpath
類(lèi)型實(shí)現(xiàn)支持SQL/JSON 路徑語(yǔ)言以有效地查詢(xún) JSON 數(shù)據(jù)。
它提供了已解析的SQL/JSON路徑表達(dá)式的二進(jìn)制表示,該表達(dá)式指定路徑引擎從JSON數(shù)據(jù)中檢索的項(xiàng),以便使用SQL/JSON查詢(xún)函數(shù)進(jìn)行進(jìn)一步處理。
SQL/JSON 路徑謂詞和運(yùn)算符的語(yǔ)義通常遵循 SQL。同時(shí),為了提供使用 JSON 數(shù)據(jù)的自然方法,SQL/JSON 路徑語(yǔ)法使用一些 JavaScript 約定:
小數(shù)點(diǎn) (.
) 用于成員訪問(wèn).
方括號(hào) ([]
) 用于數(shù)組訪問(wèn).
與從 1 開(kāi)始的常規(guī) SQL 數(shù)組不同,SQL/JSON 數(shù)組是 0 相對(duì)的。
SQL/JSON路徑表達(dá)式通常以SQL字符串文字形式寫(xiě)入SQL查詢(xún)中,因此它必須用單引號(hào)括起來(lái),并且值中需要的任何單引號(hào)都必須是雙引號(hào)(參見(jiàn) 第 4.1.2.1 節(jié))。
某些形式的路徑表達(dá)式需要其中的字符串文本。這些嵌入的字符串文本遵循JavaScript/ECMAScript約定:它們必須用雙引號(hào)括起來(lái),并且反斜杠轉(zhuǎn)義可以用于表示其他難以輸入的字符。
特別是,在嵌入字符串文本中編寫(xiě)雙引號(hào)的方法為\"
,并且要編寫(xiě)反斜杠本身,你必須寫(xiě)\\
。
包括在JSON字符串中識(shí)別的其他特殊的反斜杠序列:
\b
,
\f
,
\n
,
\r
,
\t
,
\v
對(duì)于各種 ASCII 控制字符,以及由它的4個(gè)六位數(shù)編碼點(diǎn)標(biāo)識(shí)標(biāo)識(shí)的 Unicode 字符\u
。
反斜杠語(yǔ)法還包括 JSON 不允許的兩個(gè)案例:
NNNN
\x
對(duì)于只用兩個(gè)十六進(jìn)制數(shù)字編寫(xiě)的字符代碼,以及NN
\u{
對(duì)于用 1 到 6 個(gè)十六進(jìn)制數(shù)字編寫(xiě)的字符代碼。
N...
}
路徑表達(dá)式由一系列路徑元素組成,可以是以下任何一種:
JSON基本類(lèi)型的路徑文字:Unicode文本、數(shù)字、真、假或空.
Path variables listed in 表 8.24中列出的路徑變量。
表 8.25中列出的訪問(wèn)器運(yùn)算符。
第 9.16.2.2 節(jié)中列出的jsonpath
運(yùn)算符和方法。
括號(hào),可用于提供篩選器表達(dá)式或定義路徑計(jì)算的順序。
有關(guān)使用jsonpath
具有 SQL/JSON 查詢(xún)函數(shù)的表達(dá)式的詳細(xì)信息,參見(jiàn)第 9.16.2 節(jié)。
表 8.24. jsonpath
變量
變量 | 描述 |
---|---|
$ | 表示被查詢(xún)的 JSON 值的變量(context item). |
$varname |
命名變量。其值可以由參數(shù)vars 多個(gè)JSON處理函數(shù)設(shè)置。
詳細(xì)信息請(qǐng)參見(jiàn) 表 9.47。
|
@ | 表示篩選器表達(dá)式中路徑計(jì)算結(jié)果的變量。 |
表 8.25. jsonpath
Accessors
訪問(wèn)器運(yùn)算符 | 描述 |
---|---|
|
返回具有指定密鑰的對(duì)象成員的成員訪問(wèn)器。
如果鍵名稱(chēng)是以 |
|
通配符成員訪問(wèn)器,該訪問(wèn)器返回位于當(dāng)前對(duì)象頂層的所有成員的值。 |
|
遞歸通配符成員訪問(wèn)器,它處理當(dāng)前對(duì)象JSON層次結(jié)構(gòu)的所有級(jí)別,并返回所有成員值,而不管它們的嵌套級(jí)別如何。 這是 PostgreSQL SQL/JSON 標(biāo)準(zhǔn)的擴(kuò)展。 |
|
與 |
|
數(shù)組元素訪問(wèn)器.
指定的 |
|
返回所有數(shù)組元素的通配符數(shù)組元素訪問(wèn)器。 |
對(duì)于這種目的,術(shù)語(yǔ)“值”包括數(shù)組元素,盡管 JSON 的術(shù)語(yǔ)有時(shí) 認(rèn)為數(shù)組元素與對(duì)象內(nèi)的值不同。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: