Postgresql 中文操作指南
9.16. JSON Functions and Operators #
本部分介绍:
为了在 SQL 环境中提供对 JSON 数据类型的原生支持,PostgreSQL 实现了 SQL/JSON data model。此模型包含多个项的序列。每个项可以保存 SQL 标量值,而另附加 SQL/JSON null 值,以及使用 JSON 数组和对象复合数据结构。此模型是 JSON 规范 RFC 7159 中隐含数据模型的形式化表达。
使用 SQL/JSON,你可以处理 JSON 数据和常规 SQL 数据,同时支持事务,包括:
要详细了解 SQL/JSON 标准,请参见 [id="sqltr-19075-6",role="bare"]biblio.html#SQLTR-19075-6[id="sqltr-19075-6"]。有关 PostgreSQL 中支持的 JSON 类型的详细信息,请参见 Section 8.14。
9.16.1. Processing and Creating JSON Data #
Table 9.45 显示了可用于 JSON 数据类型的运算符(请参见 Section 8.14)。此外, Table 9.1 中显示的常见比较运算符可用于 jsonb,但不能用于 json。比较运算符遵循 Section 8.14.4 中概述的 B 树操作排序规则。另请参见 Section 9.21,其中包含聚集函数 json_agg,该函数将记录值聚集为 JSON,聚集函数 json_object_agg,该函数将对值对聚集到一个 JSON 对象,以及其 jsonb 等价函数 jsonb_agg 和 jsonb_object_agg。
Table 9.45. json and jsonb Operators
Operator Description Example(s) |
json → integer → json jsonb → integer → jsonb 提取 JSON 数组的第 n 个元素(数组元素从零开始索引,但负整数从末尾开始计数)。 '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json → 2 → {"c":"baz"} '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json → -3 → {"a":"foo"} |
json → text → json jsonb → text → jsonb 使用给定的键提取 JSON 对象字段。 '{"a": {"b":"foo"}}'::json → 'a' → {"b":"foo"} |
json →> integer → text jsonb →> integer → text 提取 JSON 数组的第 n 个元素,作为 text 。 '[1,2,3]'::json →> 2 → 3 |
json →> text → text jsonb →> text → text 使用给定的键提取 JSON 对象字段作为 text 。 '{"a":1,"b":2}'::json →> 'b' → 2 |
json > text[] → json jsonb > text[] → jsonb 在指定路径下提取 JSON 子对象,其中路径元素可以是字段键或数组索引。 '{"a": {"b": ["foo","bar"]}}'::json #> '{a,b,1}' → "bar" |
json >> text[] → text jsonb >> text[] → text 将指定路径下的 JSON 子对象作为 text 提取。 '{"a": {"b": ["foo","bar"]}}'::json #>> '{a,b,1}' → bar |
Note
如果 JSON 输入没有与请求匹配的正确结构,则字段/元素/路径提取运算符将返回 NULL,而不是失败;例如,如果不存在这样的键或数组元素。
一些其他运算符仅用于 jsonb,如 Table 9.46中所示。 Section 8.14.4描述了如何使用这些运算符有效搜索索引后 _jsonb_数据。
Table 9.46. Additional jsonb Operators
Operator Description Example(s) |
jsonb @> jsonb → boolean 第一个 JSON 值是否包含第二个 JSON 值?(有关包含关系的详细信息,请参阅 Section 8.14.3 ) '{"a":1, "b":2}'::jsonb @> '{"b":2}'::jsonb → t |
jsonb <@ jsonb → boolean 第一个 JSON 值是否包含在第二个 JSON 值中? '{"b":2}'::jsonb <@ '{"a":1, "b":2}'::jsonb → t |
jsonb ? text → boolean 文本字符串是否作为 JSON 值内的顶级键或数组元素存在? '{"a":1, "b":2}'::jsonb ? 'b' → t '["a", "b", "c"]'::jsonb ? 'b' → t |
jsonb _? |
_ text[] → boolean 文本数组中的任何字符串是否作为顶级键或数组元素存在?_'{"a":1, "b":2, "c":3}'::jsonb ? |
array['b', 'd']_ → t |
jsonb ?& text[] → boolean 文本数组中的所有字符串是否作为顶级键或数组元素存在? '["a", "b", "c"]'::jsonb ?& array['a', 'b'] → t |
jsonb _ |
_ jsonb → jsonb 连接两个 jsonb 值。连接两个数组将生成一个数组,其中包含每个输入的所有元素。连接两个对象将生成一个对象,其中包含这两个对象键的并集,在出现重复键时取第二个对象的值。所有其他情况通过将非数组输入转换为单元素数组来进行处理,然后按两个数组的方式进行处理。不进行递归操作:只会合并顶级数组或对象结构。_'["a", "b"]'::jsonb |
'["a", "d"]'::jsonb_ → ["a", "b", "a", "d"] _'{"a": "b"}'::jsonb |
'{"c": "d"}'::jsonb_ → {"a": "b", "c": "d"} _'[1, 2]'::jsonb |
'3'::jsonb_ → [1, 2, 3] _'{"a": "b"}'::jsonb |
'42'::jsonb_ → [{"a": "b"}, 42] 要将一个数组作为单个条目附加到另一个数组中时,请将其包装在另一层数组中,例如:_'[1, 2]'::jsonb |
jsonb_build_array('[3, 4]'::jsonb)_ → [1, 2, [3, 4]] |
jsonb - text → jsonb 从 JSON 对象中删除一个键(及其值),或从 JSON 数组中删除匹配的字符串值。 '{"a": "b", "c": "d"}'::jsonb - 'a' → {"c": "d"} '["a", "b", "c", "b"]'::jsonb - 'b' → ["a", "c"] |
jsonb - text[] → jsonb 从左操作数中删除所有匹配的键或数组元素。 '{"a": "b", "c": "d"}'::jsonb - '{a,c}'::text[] → {} |
jsonb - integer → jsonb 删除指定索引的数组元素(负整数从末尾开始计数)。如果 JSON 值不是数组,则会引发错误。 '["a", "b"]'::jsonb - 1 → ["a"] |
jsonb #- text[] → jsonb 删除指定路径中的字段或数组元素,其中路径元素可以是字段键或数组索引。 '["a", {"b":1}]'::jsonb #- '{1,b}' → ["a", {}] |
jsonb @? jsonpath → boolean JSON 路径是否为指定的 JSON 值返回任何项目? '{"a":[1,2,3,4,5]}'::jsonb @? '$.a[*] ? (@ > 2)' → t |
jsonb @@ jsonpath → boolean 针对指定的 JSON 值返回 JSON 路径谓词检查的结果。只有结果的第一个项目会被考虑。如果结果不是布尔值,则会返回 NULL 。 '{"a":[1,2,3,4,5]}'::jsonb @@ '$.a[*] > 2' → t |
Note
jsonpath 运算符 @? 和 @@ 抑制以下错误:缺少对象字段或数组元素,意外的 JSON 项类型,日期时间和数字错误。下面描述的 jsonpath 相关函数还可以抑制这些类型的错误。在搜索结构各异的 JSON 文档集合时,此行为可能会有所帮助。
Table 9.47显示用于构建 json_和 _jsonb_值的函数。此表中的部分函数具有 _RETURNING_子句,该子句指定了返回的数据类型。它必须是 _json、jsonb、bytea、字符字符串类型 (text、char_或 _varchar)或存在从 _json_到该类型的转换的类型。默认情况下,返回 _json_类型。
Table 9.47. JSON Creation Functions
Function Description Example(s) |
to_json ( anyelement ) → json to_jsonb ( anyelement ) → jsonb 将任何 SQL 值转换为 json 或 jsonb 。数组和复合递归地转换为数组和对象(多维数组变为 JSON 中的数组数组)。否则,如果 SQL 数据类型可以转换为 json ,则将使用转换函数执行转换; [id="a",role="bare"]#ftn.id-1.5.8.22.8.9.2.2.1.1.3.4 [id="a"] 否则,将生成一个标量 JSON 值。对于除数字、布尔值或 null 值之外的任何标量,将使用文本表示形式,并根据需要进行转义以使其成为有效的 JSON 字符串值。 to_json('Fred said "Hi."'::text) → "Fred said \"Hi.\"" to_jsonb(row(42, 'Fred said "Hi."'::text)) → {"f1": 42, "f2": "Fred said \"Hi.\""} |
array_to_json ( anyarray [, boolean ] ) → json 将 SQL 数组转换为 JSON 数组。如果可选的布尔参数为 true,则行为与 to_json 相同,但高级数组元素之间会添加换行符。 array_to_json('{{1,5},{99,100}}'::int[]) → [[1,5],[99,100]] |
json_array ( [ { value_expression [ FORMAT JSON ] } [, …] ] [ { NULL |
ABSENT } ON NULL ] [ RETURNING data_type [ FORMAT JSON [ ENCODING UTF8 ] ] ]) json_array ( [ query_expression ] [ RETURNING data_type [ FORMAT JSON [ ENCODING UTF8 ] ] ])从一系列 value_expression 参数或 query_expression 的结果(必须是返回单一列的 SELECT 查询)构建 JSON 数组。如果指定了 ABSENT ON NULL ,则忽略 NULL 值。如果使用 query_expression ,则始终如此。 json_array(1,true,json '{"a":null}') → [1, true, {"a":null}] json_array(SELECT * FROM (VALUES(1),(2)) t) → [1, 2] |
row_to_json ( record [, boolean ] ) → json 将 SQL 复合值转换为 JSON 对象。如果可选的布尔参数为 true,则行为与 to_json 相同,但顶级元素之间将添加换行符。 row_to_json(row(1,'foo')) → {"f1":1,"f2":"foo"} |
json_build_array ( VARIADIC "any" ) → json jsonb_build_array ( VARIADIC "any" ) → jsonb 从一个可变参数列表中构建一个具有可能异构类型的 JSON 数组。每个参数都按 to_json 或 to_jsonb 转换。 json_build_array(1, 2, 'foo', 4, 5) → [1, 2, "foo", 4, 5] |
json_build_object ( VARIADIC "any" ) → json jsonb_build_object ( VARIADIC "any" ) → jsonb 从一个可变参数列表中构建一个 JSON 对象。根据惯例,参数列表由交替的键和值组成。键参数强制转换为文本;值参数按 to_json 或 to_jsonb 转换。 json_build_object('foo', 1, 2, row(3,'bar')) → {"foo" : 1, "2" : {"f1":3,"f2":"bar"}} |
json_object ( [ { key_expression { VALUE |
':' } value_expression [ FORMAT JSON [ ENCODING UTF8 ] ] }[, …] ] [ { NULL |
ABSENT } ON NULL ] [ { WITH |
WITHOUT } UNIQUE [ KEYS ] ] [ RETURNING data_type [ FORMAT JSON [ ENCODING UTF8 ] ] ])构build一个包含所有给定键值对的 JSON 对象,如果没有给定则构建一个空对象。 key_expression 是定义 JSON 键的标量表达式,该键转换为 text 类型。它不能是 NULL ,也不能属于具有 json 类型转换的类型。如果指定了 WITH UNIQUE KEYS ,则不能有任何重复的 key_expression 。如果指定了 ABSENT ON NULL ,则任何 value_expression 评估为 NULL 的对都会从输出中忽略;如果指定了 NULL ON NULL 或省略了该子句,则该键将包含值 NULL 。 json_object('code' VALUE 'P123', 'title': 'Jaws') → {"code" : "P123", "title" : "Jaws"} |
json_object ( text[] ) → json jsonb_object ( text[] ) → jsonb 从一个文本数组构建一个 JSON 对象。该数组必须恰好一维,其中包含偶数个成员,在这种情况下,它们被视为交替的键值对,或者两个维度,使得每个内层数组恰好有两个元素,它们被视为键值对对。所有值都转换为 JSON 字符串。 json_object('{a, 1, b, "def", c, 3.5}') → {"a" : "1", "b" : "def", "c" : "3.5"} json_object('{{a, 1}, {b, "def"}, {c, 3.5}}') → {"a" : "1", "b" : "def", "c" : "3.5"} |
json_object ( keys text[] , values text[] ) → json jsonb_object ( keys text[] , values text[] ) → jsonb 此表单 json_object 从单独文本数组中成对获取键和值。否则,它与单参数表单相同。 json_object('{a,b}', '{1,2}') → {"a": "1", "b": "2"} |
[id="a",role="bare"]#id-1.5.8.22.8.9.2.2.1.1.3.4 [id="a"] 例如, hstore 扩展从 hstore 到 json ,以便通过 JSON 创建函数转换的 hstore 值将表示为 JSON 对象,而不是原始字符串值。 |
[id="a",role="bare"]#id-1.5.8.22.8.9.2.2.1.1.3.4 [id="a"] 例如, hstore 扩展从 hstore 到 json ,以便通过 JSON 创建函数转换的 hstore 值将表示为 JSON 对象,而不是原始字符串值。
Table 9.48详细介绍用于测试 JSON 的 SQL/JSON 功能。
Table 9.48. SQL/JSON Testing Functions
Function signature Description Example(s) |
expression IS [ NOT ] JSON [ { VALUE |
SCALAR |
ARRAY |
OBJECT } ] [ { WITH |
WITHOUT } UNIQUE [ KEYS ] ]该谓词测试是否可以将 expression 解析为 JSON,可能是指定类型的 JSON。如果指定了 SCALAR 、 ARRAY 或 OBJECT ,测试的内容就是 JSON 是否属于该特定类型。如果指定了 WITH UNIQUE KEYS ,则还测试 expression 中的任何对象以查看它是否具有重复的键。SELECT js, js IS JSON "json?", js IS JSON SCALAR "scalar?", js IS JSON OBJECT "object?", js IS JSON ARRAY "array?"FROM (VALUES ('123'), ('"abc"'), ('{"a": "b"}'), ('[1,2]'),('abc')) foo(js); js |
json? |
scalar? |
object? |
array? --------------------------------------------- 123 |
t |
t |
f |
f "abc" |
t |
t |
f |
f {"a": "b"} |
t |
f |
t |
f [1,2] |
t |
f |
f |
t abc |
f |
f |
f |
fSELECT js, js IS JSON OBJECT "object?", js IS JSON ARRAY "array?", js IS JSON ARRAY WITH UNIQUE KEYS "array w. UK?", js IS JSON ARRAY WITHOUT UNIQUE KEYS "array w/o UK?"FROM (VALUES ('[{"a":"1"}, {"b":"2","b":"3"}]')) foo(js);-[ RECORD 1 ]-+--------------------js |
[{"a":"1"}, |
{"b":"2","b":"3"}] object? |
f array? |
t array w. UK? |
f array w/o UK? |
t |
Table 9.49显示用于处理 _json_和 _jsonb_值的函数。
Table 9.49. JSON Processing Functions
Function Description Example(s) |
json_array_elements ( json ) → setof json jsonb_array_elements ( jsonb ) → setof jsonb 将顶级 JSON 数组扩展为一组 JSON 值。 select * from json_array_elements('[1,true, [2,false]]') → value---- 1 true [2,false]---- |
json_array_elements_text ( json ) → setof text jsonb_array_elements_text ( jsonb ) → setof text 将顶级 JSON 数组扩展为一组 text 值。 select * from json_array_elements_text('["foo", "bar"]') → value---- foo bar---- |
json_array_length ( json ) → integer jsonb_array_length ( jsonb ) → integer 返回顶级 JSON 数组中元素的数量。 json_array_length('[1,2,3,{"f1":1,"f2":[5,6]},4]') → 5 jsonb_array_length('[]') → 0 |
json_each ( json ) → setof record ( key text , value json ) jsonb_each ( jsonb ) → setof record ( key text , value jsonb )将顶级 JSON 对象扩展为一组键/值对。 select * from json_each('{"a":"foo", "b":"bar"}') → key |
value -----+------- a |
"foo" b |
"bar" |
json_each_text ( json ) → setof record ( key text , value text ) jsonb_each_text ( jsonb ) → setof record ( key text , value text )将顶级 JSON 对象扩展为一组键/值对。返回的 value_s will be of type _text . select * from json_each_text('{"a":"foo", "b":"bar"}') → key |
value -----+------- a |
foo b |
bar |
json_extract_path ( from_json json , VARIADIC path_elems text[] ) → json jsonb_extract_path ( from_json jsonb , VARIADIC path_elems text[] ) → jsonb 在指定路径处提取 JSON 子对象。(这在功能上等效于 #> 运算符,但在某些情况下,将路径写为变参列表可能会更方便。) json_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}', 'f4', 'f6') → "foo" |
json_extract_path_text ( from_json json , VARIADIC path_elems text[] ) → text jsonb_extract_path_text ( from_json jsonb , VARIADIC path_elems text[] ) → text 在指定路径处作为 text 提取 JSON 子对象。(这在功能上等效于 #>> 运算符。) json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}', 'f4', 'f6') → foo |
json_object_keys ( json ) → setof text jsonb_object_keys ( jsonb ) → setof text 返回顶级 JSON 对象中的键集。 select * from json_object_keys('{"f1":"abc","f2":{"f3":"a", "f4":"b"}}') → json_object_keys---- f1 f2---- |
json_populate_record ( base anyelement , from_json json ) → anyelement jsonb_populate_record ( base anyelement , from_json jsonb ) → anyelement 将顶级 JSON 对象扩展为具有 base 参数的复合类型的行。扫描 JSON 对象以查找其名称与输出行类型的列名称匹配的字段,并将这些字段的值插入到输出的这些列中。(与任何输出列名称不对应的字段将被忽略。)在典型用法中, base 的值只是 NULL ,这意味着任何与任何对象字段不匹配的输出列都将用 null 填充。但是,如果 base 不是 NULL ,则它所包含的值将用于不匹配的列。要将 JSON 值转换为输出列的 SQL 类型,将按顺序应用以下规则:JSON null 值在所有情况下都将转换为 SQL null。如果输出列是 json 或 jsonb 类型,则 JSON 值将被精确复制。如果输出列是复合(行)类型,并且 JSON 值是 JSON 对象,则将通过递归应用这些规则将对象的字段转换为输出行类型的列。同样,如果输出列是数组类型且 JSON 值是 JSON 数组,则将通过递归应用这些规则将 JSON 数组的元素转换为输出数组的元素。否则,如果 JSON 值是字符串,则将字符串的内容馈送给列数据类型的输入转换函数。否则,将 JSON 值的普通文本表示形式馈送给列数据类型的输入转换函数。虽然下面的示例使用了一个常量 JSON 值,但典型的用法是横向引用查询 FROM 子句中其他表中的 json 或 jsonb 列。在 FROM 子句中写入 json_populate_record 是一个好习惯,因为所有提取的列都可以使用,而无需重复调用函数。 create type subrowtype as (d int, e text); create type myrowtype as (a int, b text[], c subrowtype); select * from json_populate_record(null::myrowtype, '{"a": 1, "b": ["2", "a b"], "c": {"d": 4, "e": "a b c"}, "x": "foo"}') → a |
b |
c --------------------------- 1 |
{2,"a b"} |
(4,"a b c") |
json_populate_recordset ( base anyelement , from_json json ) → setof anyelement jsonb_populate_recordset ( base anyelement , from_json jsonb ) → setof anyelement 将对象顶级 JSON 数组扩展为具有 base 参数的复合类型的行集。对 JSON 数组的每个元素的处理方式如 json[b]_populate_record 中所述。 create type twoints as (a int, b int); select * from json_populate_recordset(null::twoints, '[{"a":1,"b":2}, {"a":3,"b":4}]') → a |
b ---+--- 1 |
2 3 |
4 |
json_to_record ( json ) → record jsonb_to_record ( jsonb ) → record 将顶级 JSON 对象扩展为具有 AS 子句定义的复合类型的行。(与所有返回 record 的函数一样,调用查询必须使用 AS 子句明确定义记录结构。)以与 json[b]_populate_record 中描述的方式相同,用 JSON 对象的字段填充输出记录。由于没有输入记录值,因此不匹配的列始终填充为 null。 create type myrowtype as (a int, b text); select * from json_to_record('{"a":1,"b":[1,2,3],"c":[1,2,3],"e":"bar","r": {"a": 123, "b": "a b c"}}') as x(a int, b text, c int[], d text, r myrowtype) → a |
b |
c |
d |
r --------------------------------------- 1 |
[1,2,3] |
{1,2,3} |
(123,"a b c") |
json_to_recordset ( json ) → setof record jsonb_to_recordset ( jsonb ) → setof record 将对象的最顶层 JSON 数组扩展到一组行,其复合类型由 AS 子句定义。(与返回 record 的所有函数一样,调用查询必须使用 AS 子句显式定义记录结构。)JSON 数组的每一个元素都按照上文 json[b]_populate_record 所述进行处理。 select * from json_to_recordset('[{"a":1,"b":"foo"}, {"a":"2","c":"bar"}]') as x(a int, b text) → a |
b ---+----- 1 |
foo 2 |
jsonb_set ( target jsonb , path text[] , new_value jsonb [, create_if_missing boolean ] ) → jsonb 如果 create_if_missing 为真(这是默认设置)并且由 path 指定的项目不存在,则返回 target ,其中由 path 指定的项目被 new_value 替换,或者在 create_if_missing 为真时使用 new_value 添加。路径中的所有早期步骤都必须存在,否则 target 将保持不变。与基于路径的操作员一样,出现在 path 中的负整数从 JSON 数组结尾计数。如果最后一个路径步骤是超出范围的数组索引,并且 create_if_missing 为真,则如果索引为负数,新值将被添加到数组开头;如果为正数,则被添加到数组结尾。 jsonb_set('[{"f1":1,"f2":null},2,null,3]', '{0,f1}', '[2,3,4]', false) → [{"f1": [2, 3, 4], "f2": null}, 2, null, 3] jsonb_set('[{"f1":1,"f2":null},2]', '{0,f3}', '[2,3,4]') → [{"f1": 1, "f2": null, "f3": [2, 3, 4]}, 2] |
jsonb_set_lax ( target jsonb , path text[] , new_value jsonb [, create_if_missing boolean [, null_value_treatment text ]] ) → jsonb 如果 new_value 不为 NULL ,则与 jsonb_set 的行为相同。否则,根据 null_value_treatment 的值进行处理,该值必须为 'raise_exception' 、 'use_json_null' 、 'delete_key' 或 'return_target' 之一。默认值为 'use_json_null' 。 jsonb_set_lax('[{"f1":1,"f2":null},2,null,3]', '{0,f1}', null) → [{"f1": null, "f2": null}, 2, null, 3] jsonb_set_lax('[{"f1":99,"f2":null},2]', '{0,f3}', null, true, 'return_target') → [{"f1": 99, "f2": null}, 2] |
jsonb_insert ( target jsonb , path text[] , new_value jsonb [, insert_after boolean ] ) → jsonb 返回已插入 new_value 的 target 。如果 path 指定的元素是一个数组元素,则 new_value 将在该元素之前(默认为 insert_after 为 false)或在该元素之后(如果 insert_after 为 true)插入。如果 path 指定的元素是一个对象字段,则只有在对象尚未包含该键的情况下才会插入 new_value 。路径中的所有早期步骤都必须存在,否则将 target 返回为未更改的状态。与面向路径的操作符一样,出现在 path 中的负整数从 JSON 数组的尾部开始计算。如果最后路径步骤是一个超出范围的数组索引,则如果该索引为负数,则新值将添加到数组的开头;如果该索引为正数,则添加到数组的末尾。 jsonb_insert('{"a": [0,1,2]}', '{a, 1}', '"new_value"') → {"a": [0, "new_value", 1, 2]} jsonb_insert('{"a": [0,1,2]}', '{a, 1}', '"new_value"', true) → {"a": [0, 1, "new_value", 2]} |
json_strip_nulls ( json ) → json jsonb_strip_nulls ( jsonb ) → jsonb 递归地删除具有空值的、给定的 JSON 值中的所有对象字段。不会更改不是对象字段的空值。 json_strip_nulls('[{"f1":1, "f2":null}, 2, null, 3]') → [{"f1":1},2,null,3] |
jsonb_path_exists ( target jsonb , path jsonpath [, vars jsonb [, silent boolean ]] ) → boolean 检查 JSON 路径是否为指定 JSON 值返回任何元素。如果指定 vars 参数,则该参数必须是一个 JSON 对象,且它的字段为提供要替代进 jsonpath 表达式中的命名值。如果指定 silent 参数且为 true ,则该函数将抑制 @? 和 @@ 运算符抑制的相同错误。 jsonb_path_exists('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ ⇐ $max)', '{"min":2, "max":4}') → t |
jsonb_path_match ( target jsonb , path jsonpath [, vars jsonb [, silent boolean ]] ) → boolean 返回对指定 JSON 值的 JSON 路径谓词检查的结果。仅考虑结果的第一个元素。如果不是布尔值,则返回 NULL 。可选 vars 和 silent 参数的作用与 jsonb_path_exists 相同。 jsonb_path_match('{"a":[1,2,3,4,5]}', 'exists($.a[*] ? (@ >= $min && @ ⇐ $max))', '{"min":2, "max":4}') → t |
jsonb_path_query ( target jsonb , path jsonpath [, vars jsonb [, silent boolean ]] ) → setof jsonb 返回指定 JSON 值的 JSON 路径返回的所有 JSON 元素。可选 vars 和 silent 参数的作用与 jsonb_path_exists 相同。 select * from jsonb_path_query('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ ⇐ $max)', '{"min":2, "max":4}') → jsonb_path_query---- 2 3 4---- |
jsonb_path_query_array ( target jsonb , path jsonpath [, vars jsonb [, silent boolean ]] ) → jsonb 返回经 JSON 路径作为 JSON 数组转换的指定 JSON 值返回的所有 JSON 元素。可选 vars 和 silent 参数的作用与 jsonb_path_exists 相同。 jsonb_path_query_array('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ ⇐ $max)', '{"min":2, "max":4}') → [2, 3, 4] |
jsonb_path_query_first ( target jsonb , path jsonpath [, vars jsonb [, silent boolean ]] ) → jsonb 返回指定 JSON 值的 JSON 路径返回的第一个 JSON 元素。如果不存在结果,则返回 NULL 。可选 vars 和 silent 参数的作用与 jsonb_path_exists 相同。 jsonb_path_query_first('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ ⇐ $max)', '{"min":2, "max":4}') → 2 |
jsonb_path_exists_tz ( target jsonb , path jsonpath [, vars jsonb [, silent boolean ]] ) → boolean jsonb_path_match_tz ( target jsonb , path jsonpath [, vars jsonb [, silent boolean ]] ) → boolean jsonb_path_query_tz ( target jsonb , path jsonpath [, vars jsonb [, silent boolean ]] ) → setof jsonb jsonb_path_query_array_tz ( target jsonb , path jsonpath [, vars jsonb [, silent boolean ]] ) → jsonb jsonb_path_query_first_tz ( target jsonb , path jsonpath [, vars jsonb [, silent boolean ]] ) → jsonb 这些函数的行为与上面描述的那些没有 _tz 后缀的对应函数类似,但这些函数支持需要时区感知转换的日期/时间值的比较。下面的示例需要将日期值 2015-08-02 解释为具有时区的 timestamp,因此结果取决于当前 TimeZone 设置。由于此依赖关系,这些函数标记为 “稳定”,这意味着这些函数不能在索引中使用。它们的对应函数是不可变的,因此可以在索引中使用;但如果要求进行此类比较,它们会引发错误。 jsonb_path_exists_tz('["2015-08-01 12:00:00-05"]', '$[*] ? (@.datetime() < "2015-08-02".datetime())') → t |
jsonb_pretty ( jsonb ) → text 将给定的 JSON 值转换为格式良好的缩进文本。 jsonb_pretty('[{"f1":1,"f2":null}, 2]') →[ { "f1": 1, "f2": null }, 2] |
json_typeof ( json ) → text jsonb_typeof ( jsonb ) → text 返回顶级 JSON 值的类型作为文本字符串。可能的类型为 object 、 array 、 string 、 number 、 boolean 和 null 。( null 结果不应与 SQL NULL 相混淆;请参见示例。) json_typeof('-123.4') → number json_typeof('null'::json) → null json_typeof(NULL::json) IS NULL → t |
9.16.2. The SQL/JSON Path Language #
SQL/JSON 路径表达式指定要从 JSON 数据中检索的项目,类似于 SQL 访问 XML 时使用的 XPath 表达式。在 PostgreSQL 中,路径表达式实现为 jsonpath 数据类型,并且可以使用 Section 8.14.7 中所述的任何元素。
JSON 查询函数和运算符将提供的路径表达式传递到 path engine 以进行评估。如果表达式与查询的 JSON 数据匹配,则返回相应的 JSON 项或一组项。路径表达式是用 SQL/JSON 路径语言编写的,可以包括算术表达式和函数。
路径表达式由 jsonpath 数据类型允许的一序列元素组成。路径表达式通常是从左到右求值的,但可以使用括号来更改操作顺序。如果求值成功,则生成一系列 JSON 项,并将求值结果返回给 JSON 查询函数以完成指定的计算。
若要引用正在查询的 JSON 值(即 context item),请在路径表达式中使用 $ 变量。其后可以跟随一个或多个 accessor operators,它们逐层进入 JSON 结构以检索上下文项目子项目。随后的每个运算符都处理前一个评估步骤的结果。
例如,假设您有一些来自 GPS 跟踪器的 JSON 数据,您想要对它们进行解析,例如:
{
"track": {
"segments": [
{
"location": [ 47.763, 13.4034 ],
"start time": "2018-10-14 10:05:14",
"HR": 73
},
{
"location": [ 47.706, 13.2635 ],
"start time": "2018-10-14 10:39:21",
"HR": 135
}
]
}
}
要检索可用音轨段,您需要使用 ._key_ 访问符运算符来向下导航周围的 JSON 对象:
$.track.segments
若要检索数组的内容,您通常会使用 [*] 运算符。例如,以下路径将返回所有可用跟踪段的位置坐标:
$.track.segments[*].location
若仅返回第一段的坐标,您可以在 [] 访问运算符中指定对应的下标。回想一下,JSON 数组的索引是从 0 开始的:
$.track.segments[0].location
可以通过 Section 9.16.2.2 中列出的一个或多个 jsonpath 运算符和方法来处理每个路径评估步骤的结果。每个方法名前面都必须加一个句点。例如,您可以获取一个数组的大小:
$.track.segments.size()
以下 Section 9.16.2.2 中显示了在路径表达式内使用 jsonpath 运算符和方法的更多示例。
在定义路径时,您还可以使用一个或多个 filter expressions,它们与 SQL 中的 WHERE 从句类似。筛选表达式以问号开头,并在括号中提供条件:
? (condition)
筛选表达式必须在应用它的路径计算步骤之后立即编写。该步骤的结果将经过筛选,仅包括那些满足提供的条件的项。SQL/JSON 定义了三值逻辑,因此条件可以是 true、false 或 unknown。unknown 值与 SQL NULL 扮演相同的角色,可以使用 is unknown 谓词对它进行测试。进一步的路径计算步骤仅使用筛选表达式返回 true 的那些项。
可在筛选表达式中使用的函数和运算符列在 Table 9.51 中。在筛选表达式内,@ 变量表示正在筛选的值(即前一个路径步骤的一个结果)。您可以在 @ 后面编写访问运算符来检索组件项。
例如,假设您想要检索所有高于 130 的心率值。您可以使用以下表达式来实现:
$.track.segments[*].HR ? (@ > 130)
要获取具有此类值段的开始时间,您需要在返回开始时间之前过滤出不相关的段,因此筛选表达式应用于前一步,并且条件中使用的路径不同:
$.track.segments[*] ? (@.HR > 130)."start time"
如果需要,您可以按顺序使用多个筛选表达式。例如,以下表达式选择所有轨迹段中的开始时间,这些轨迹段包含具有相关坐标和高心率值的位置:
$.track.segments[*] ? (@.location[1] < 13.4) ? (@.HR > 130)."start time"
还允许在不同嵌套级别使用筛选表达式。以下示例首先按位置筛选所有段,然后为这些段返回较高的最高心率值(如果可用):
$.track.segments[*] ? (@.location[1] < 13.4).HR ? (@ > 130)
您还可以在彼此内部嵌套筛选表达式:
$.track ? (exists(@.segments[*] ? (@.HR > 130))).segments.size()
此表达式返回轨迹的大小,如果它包含具有高心率值的任何段,否则返回一个空序列。
PostgreSQL 对 SQL/JSON 路径语言的实现与 SQL/JSON 标准有以下差异:
9.16.2.1. Strict and Lax Modes #
当您查询 JSON 数据时,路径表达式可能与实际 JSON 数据结构不匹配。尝试访问对象的不存在的成员或数组的元素会导致结构错误。SQL/JSON 路径表达式有两种处理结构错误的方式:
如果 JSON 数据不符合预期的模式,宽松模式有助于匹配 JSON 文档结构和路径表达式。如果运算数不满足特定操作的要求,则它可以自动包装为 SQL/JSON 数组或解包,方法是在执行此操作之前将其实例转换为 SQL/JSON 序列。此外,在宽松模式中,比较运算符会自动解包它们的运算数,因此您可以直接比较 SQL/JSON 数组。大小为 1 的数组被认为等于其唯一元素。只有在以下情况下才不执行自动解包:
例如,在查询上述 GPS 数据时,在使用宽松模式时,您可以忽略它存储段的数组这一事实:
lax $.track.segments.location
在严格模式下,指定路径必须与查询的 JSON 文档的结构完全匹配,才能返回 SQL/JSON 项,因此使用此路径表达式会导致错误。要获得与宽松模式相同的结果,必须明确解包 segments 数组:
strict $.track.segments[*].location
在使用宽松模式时,.** 访问器可能会导致令人惊讶的结果。例如,以下查询选择每个 HR 值两次:
lax $.**.HR
这是因为 .* 访问器同时选择了 segments 数组及其每个元素,而 .HR 访问器在使用宽松模式时自动解包数组。为避免令人惊讶的结果,我们建议仅在严格模式下使用 .* 访问器。以下查询仅选择每个 HR 值一次:
strict $.**.HR
9.16.2.2. SQL/JSON Path Operators and Methods #
Table 9.50 显示了 jsonpath 中可用的运算符和方法。请注意,虽然一元运算符和方法可以应用于由前一个路径步骤产生的多个值,但二元运算符(加法等)只能应用于单个值。
Table 9.50. jsonpath Operators and Methods
Operator/Method Description Example(s) |
number + number → number 加法 jsonb_path_query('[2]', '$[0] + 3') → 5 |
+ number → number 一元加号(无运行);与加法不同,它能够遍历多个值 jsonb_path_query_array('{"x": [2,3,4]}', '+ $.x') → [2, 3, 4] |
number - number → number 减法 jsonb_path_query('[2]', '7 - $[0]') → 5 |
- number → number 取反;与减法不同,这可以对多个值进行迭代 jsonb_path_query_array('{"x": [2,3,4]}', '- $.x') → [-2, -3, -4] |
number * number → number 乘法 jsonb_path_query('[4]', '2 * $[0]') → 8 |
number / number → number 除法 jsonb_path_query('[8.5]', '$[0] / 2') → 4.2500000000000000 |
number % number → number 模数(余数) jsonb_path_query('[32]', '$[0] % 10') → 2 |
value . type() → string JSON 项目类型(见 json_typeof ) jsonb_path_query_array('[1, "2", {}]', '$[*].type()') → ["number", "string", "object"] |
value . size() → number JSON 项目大小(数组元素数,若非数组则为 1) jsonb_path_query('{"m": [11, 15]}', '$.m.size()') → 2 |
value . double() → number 从 JSON 数或字符串转换来的近似浮点数 jsonb_path_query('{"len": "1.9"}', '$.len.double() * 2') → 3.8 |
number . ceiling() → number 大于或等于给定数的最近整数 jsonb_path_query('{"h": 1.3}', '$.h.ceiling()') → 2 |
number . floor() → number 小于或等于给定数的最近整数 jsonb_path_query('{"h": 1.7}', '$.h.floor()') → 1 |
number . abs() → number 给定数的绝对值 jsonb_path_query('{"z": -0.3}', '$.z.abs()') → 0.3 |
string . datetime() → datetime_type (见注释)从字符串转换来的日期/时间值 jsonb_path_query('["2015-8-1", "2015-08-12"]', '$[*] ? (@.datetime() < "2015-08-2".datetime())') → "2015-8-1" |
string . datetime(_template )_ → datetime_type (见注释)使用指定的 to_timestamp 模板从字符串转换来的日期/时间值 jsonb_path_query_array('["12:30", "18:40"]', '$[*].datetime("HH24:MI")') → ["12:30:00", "18:40:00"] |
object . keyvalue() → array 对象的键值对,表示为一个数组,其中包含三个字段的对象: "key" 、 "value" 和 "id" ; "id" 是键值对所属对象的唯一标识符 jsonb_path_query_array('{"x": "20", "y": 32}', '$.keyvalue()') → [{"id": 0, "key": "x", "value": "20"}, {"id": 0, "key": "y", "value": 32}] |
Note
datetime() 和 datetime(_template)_ 方法的结果类型可以是 date、timetz、time、timestamptz 或 timestamp。两种方法都动态地确定其结果类型。
datetime() 方法循序渐进地尝试匹配其输入字符串与 date、timetz、time、timestamptz 和 timestamp 的 ISO 格式。它在第一个匹配的格式上停止并发出相应的数据类型。
datetime(_template)_ 方法根据提供模板字符串中使用的字段确定结果类型。
datetime()_和 _datetime(_template)_) 方法使用与 _to_timestamp_SQL 函数相同的解析规则(参见 Section 9.8),但有三个例外。第一,这些方法不允许不匹配的模板模式。第二,模板字符串中只允许使用以下分隔符:减号、句点、斜杠(反斜杠)、逗号、撇号、分号、冒号和空格。第三,模板字符串中的分隔符必须与输入字符串完全匹配。
如果需要比较不同的日期/时间类型,则会应用隐式强制转换。date_值可以强制转换为 _timestamp_或 _timestamptz,timestamp_可以强制转换为 _timestamptz,而 time_可以强制转换为 _timetz。但是,除了第一个转换之外,其他所有转换都依赖于当前 TimeZone设置,因此只能在支持时区的 _jsonpath_函数中执行。
Table 9.51显示了可用的筛选器表达式元素。
Table 9.51. jsonpath Filter Expression Elements
Predicate/Value Description Example(s) |
value == value → boolean 相等比较(该比较器和其他比较运算符在所有 JSON 标量值上起作用) jsonb_path_query_array('[1, "a", 1, 3]', '$[] ? (@ == 1)') → [1, 1] jsonb_path_query_array('[1, "a", 1, 3]', '$[] ? (@ == "a")') → ["a"] |
value != value → boolean value <> value → boolean 不相等比较 jsonb_path_query_array('[1, 2, 1, 3]', '$[] ? (@ != 1)') → [2, 3] jsonb_path_query_array('["a", "b", "c"]', '$[] ? (@ <> "b")') → ["a", "c"] |
value < value → boolean 小于比较 jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ < 2)') → [1] |
value ⇐ value → boolean 小于或等于比较 jsonb_path_query_array('["a", "b", "c"]', '$[*] ? (@ ⇐ "b")') → ["a", "b"] |
value > value → boolean 大于比较 jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ > 2)') → [3] |
value >= value → boolean 大于或等于比较 jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ >= 2)') → [2, 3] |
true → boolean JSON 常量 true jsonb_path_query('[{"name": "John", "parent": false}, {"name": "Chris", "parent": true}]', '$[*] ? (@.parent == true)') → {"name": "Chris", "parent": true} |
false → boolean JSON 常量 false jsonb_path_query('[{"name": "John", "parent": false}, {"name": "Chris", "parent": true}]', '$[*] ? (@.parent == false)') → {"name": "John", "parent": false} |
null → value JSON 常量 null (注意,与 SQL 中不同,比较 null 按正常方式工作) jsonb_path_query('[{"name": "Mary", "job": null}, {"name": "Michael", "job": "driver"}]', '$[*] ? (@.job == null) .name') → "Mary" |
boolean && boolean → boolean 布尔 AND jsonb_path_query('[1, 3, 7]', '$[*] ? (@ > 1 && @ < 5)') → 3 |
boolean _ |
_ boolean → boolean 布尔 OR_jsonb_path_query('[1, 3, 7]', '$[*] ? (@ < 1 |
@ > 5)')_ → 7 |
! boolean → boolean 布尔 NOT jsonb_path_query('[1, 3, 7]', '$[*] ? (!(@ < 5))') → 7 |
boolean is unknown → boolean 测试布尔条件是否为 unknown . jsonb_path_query('[-1, 2, 7, "foo"]', '$[*] ? ((@ > 0) is unknown)') → "foo" |
string like_regex string [ flag string ] → boolean 测试第一个操作数是否匹配第二个操作数给出的正则表达式,也可以使用字符串 flag 字符描述来进行可选修改(请参阅 Section 9.16.2.3 )。 jsonb_path_query_array('["abc", "abd", "aBdC", "abdacb", "babc"]', '$[] ? (@ like_regex "^ab.*c")') → ["abc", "abdacb"] jsonb_path_query_array('["abc", "abd", "aBdC", "abdacb", "babc"]', '$[] ? (@ like_regex "^ab.*c" flag "i")') → ["abc", "aBdC", "abdacb"] |
string starts with string → boolean 测试第二个操作数是否是第一个操作数的初始子串。 jsonb_path_query('["John Smith", "Mary Stone", "Bob Johnson"]', '$[*] ? (@ starts with "John")') → "John Smith" |
exists ( path_expression ) → boolean 测试路径表达式是否至少匹配一个 SQL/JSON 项目。如果路径表达式导致错误,则返回 unknown ;第二个示例在严格模式下使用它来避免因不存在密钥而导致的错误。 jsonb_path_query('{"x": [1, 2], "y": [2, 4]}', 'strict $.* ? (exists (@ ? (@[*] > 2)))') → [2, 4] jsonb_path_query_array('{"value": 41}', 'strict $ ? (exists (@.name)) .name') → [] |
9.16.2.3. SQL/JSON Regular Expressions #
SQL/JSON 路径表达式允许使用 like_regex 过滤器将文本与正则表达式进行匹配。例如, 以下 SQL/JSON 路径查询将不区分大小写地匹配数组中以英语元音开头的所有字符串:
$[*] ? (@ like_regex "^[aeiou]" flag "i")
可选的 flag 字符串可以包含一个或多个用于不区分大小写匹配的字符 i,用于允许 ^ 和 $ 换行匹配的 m,用于允许 . 换行匹配的 s 以及用于引用整个模式(将行为简化为简单的子字符串匹配)的 q。
SQL/JSON 标准借用其对于 LIKE_REGEX 操作符的正则表达式的定义,而该操作符又使用 XQuery 标准。PostgreSQL 目前不支持 LIKE_REGEX 操作符。因此, like_regex 过滤器是使用 Section 9.7.3 中描述的 POSIX 正则表达式引擎实现的。这会产生各种小偏差,使其偏离标准 SQL/JSON 行为,这些偏差已在 Section 9.7.3.8 中编入目录。但是请注意,此处描述的标记字母不兼容不适用于 SQL/JSON,因为它将 XQuery 标记字母转换为匹配 POSIX 引擎的字母。
请记住, like_regex 的模式参数是 JSON 路径字符串文本,根据 Section 8.14.7 中给出的规则编写。这意味着,正则表达式中想要使用的任何反斜杠都必须加倍。例如,要匹配仅包含数字的根文档的字符串值:
$.* ? (@ like_regex "^\\d+$")