跳转至

使用JSON数据

使用JSON数据

SeaboxMPP数据库支持jsonjsonb数据类型来存储JSON (JavaScript Object Notation)数据。

SeaboxMPP数据库按照文档RFC 7159支持JSON,并且根据JSON规则强制数据有效性。也有一些用于jsonjsonb数据类型的JSON相关的函数和操作符。

SeaboxMPP数据库包含创建和操作JSON数据的内置函数和运算符。

注意:对于json数据类型值,即使JSON对象包含重复的键,也会保留所有键/值对。对于重复的键,JSON处理函数将最后一个值视为可操作的值。对于JSONB数据类型,不保留重复的对象键。如果输入包含重复键,则只保留最后一个值。请参见关于JSON数据

关于JSON数据

SeaboxMPP数据库支持两种JSON数据类型: jsonjsonb. 他们输入值基本一致,主要区别之一是效率。

  • json数据类型存储输入副本. 这要求JSON处理函数每次执行时处理json数据。json数据类型不会修改输入文本。

    • 记号之间没有语义意义的空格被保留,JSON对象内的键的顺序也被保留。

    • 即便JSON对象含有重复键,所有的键/值对也会被保留。对于重复键,JSON处理函数把其中的最后一个值当作有效值。

  • jsonb数据类型存储输入文本的二进制格式。输入数据的转换开销使jsonb稍慢于 json数据类型. 但是,json处理函数明显更快,因为解析jsonb数据不是必须的。 jsonb数据类型修改输入文本。

    • 空格不保留

    • 对象内的键的顺序不保留

    • 重复键对象不保留,如果输入包含重复键,仅保留最后一个值。

SeaboxMPP数据库jsonb数据类型支持GIN, btree,和hash索引。

一般来说,JSON数据应该存储为jsonb数据类型,除非特殊需要,例如关于对象键顺序的遗留假设。

  • JSON数据中的Unicode字符说明如下:

RFC 7159文档允许JSON字符串包含表示为\uXXXX的Unicode转义序列。不过,SeaboxMPP对每一个数据库只允许一种字符集编码。

除非数据库编码为UTF8,json类型不可能严格地符合JSON说明。尝试包括数据库编码中无法表示的字符将会失败。允许可在数据库编码中表示但不在UTF8中的字符。

- `json`数据类型的SeaboxMPP数据库输入函数允许unicode转义,而无论是什么数据库编码,只检查unicode转义的语法正确性(`\u`后跟四个十六进制数字)。

- `jsonb`数据类型的SeaboxMPP数据库输入函数更严格。它不允许非ASCII字符(`U+007F`以上的字符)使用Unicode转义,除非数据库编码是UTF8。它还拒绝`\u0000`,它不能在SeaboxMPP数据库`text`类中表示,并且它要求使用unicode代理项对指定unicode基本多语言平面之外的字符是正确的。有效的Unicode转义符(除了`\u0000`)转换为等效的ASCII或UTF8字符进行存储;这包括将代理项对折叠为单个字符。

注意:JSON函数和运算符中描述的许多JSON处理函数将Unicode转义转换为常规字符。函数对数据库编码中无法表示的字符抛出错误。如果可能的话,应该避免将JSON中的Unicode转义与非UTF8数据库编码混合在一起。

  • JSON数据类型与SeaboxMPP数据类型的映射说明如下:

当将JSON文本的数据转换为jsonb数据时,RFC 7159描述的原始数据类型可映射为SeaboxMPP数据库中的数据类型如下表所示。

表 将JSON数据类型映射到SeaboxMPP数据类型

JSON原始数据类型 SeaboxMPP数据库数据类型 注意
string text 不允许使用\u0000。只有当数据库编码为utf8时,才允许使用非ASCII Unicode转义。
number numeric 不允许使用NaNinfinity
boolean boolean 只接受小写的正误拼写
null (none) The JSON null 原始类型不同于SQL NULL

对于有效的jsonb 数据的构成有一些次要的约束,这些约束既不适用于json数据类型,也不适用于抽象的JSON,对应于基础数据类型所能表示的限制。值得注意的是,当将数据转换为jsonb数据类型时,超出SeaboxMPP数据库numeric数据类型范围的数字将被拒绝,而json数据类型不会拒绝这些数字。

RFC 7159允许这种实施定义的限制。然而,在实践中,这些问题可能会出现在其他实现中,因为通常将JSON原始类型number表示为IEEE 754双精度浮点(RFC7159明确预测并允许)。

当使用JSON作为与其他系统的交换格式时,请注意与SeaboxMPP数据库最初存储的数据相比,数字精度可能会降低。

另外,正如上表中所指出的,对于JSON原语类型的输入格式,存在一些小的限制,这些限制不适用于相应的SeaboxMPP数据库数据类型。

输入输出语法

json数据类型的输入和输出语法如RFC 7159中所述。

下列都是合法的json表达式:

-- 简单标量/原始值
-- 原始值值可以是数字、带引号的字符串、true、false或者null SELECT '5'::json;

-- 零个或者更多个元素的数组(元素类型可以不同)
          SELECT '[1, 2, "foo", null]'::json;

-- 含有键/值对的对象
-- 注意对象的键必须总是带引号的字符串
SELECT '{"bar": "baz", "balance": 7.77, "active": false}'::json;

-- 数组和对象可以任意嵌套
SELECT '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}'::json;

如前所述,当输入JSON值,然后在不进行任何附加处理的情况下打印时,json数据类型输出的文本与输入的文本相同,而jsonb数据类型不保留语义上不重要的细节,如空白。例如,请注意这里的区别:

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)

值得注意的一个语义上不重要的细节是,对于jsonb数据类型,将根据基础数字类型的行为打印数字。在实践中,这意味着使用e符号输入的数字将不使用e符号打印,例如:

SELECT '{"reading": 1.230e-5}'::json, '{"reading": 1.230e-5}'::jsonb;
         json          |          jsonb          
-----------------------+-------------------------
 {"reading": 1.230e-5} | {"reading": 0.00001230}
(1 row)

然而, jsonb数据类型保留了尾随的小数零,如前一个示例中所示,即使这些小数零在语义上对于诸如相等性检查之类的是无关紧要的。

JSON使用设计原则

将数据表示为JSON比传统关系数据模型要更灵活,在需求变化的环境中表现得尤其明显。在同一个应用中很可能两种方法会共存并且成为彼此的互补。不过,即便是对于要求最大灵活性的应用中,我们仍然推荐JSON有些许固定的结构。这种结构是非强制的(尽管可能会强制一些业务规则),但是如果有可预测的结构会让编写有效汇总表中一组“文档”(数据)的查询更容易。

在表中存储时,JSON数据服从和其他任何数据类型一样的并发控制考虑。尽管存储大型文档格式可行的,但要记住任何更新都要求整个行上的一个行级锁。为了降低更新事务之间的锁竞争,请考虑限制JSON文档为一个可管理的尺寸。理想上,每个JSON文档应该表示业务规则规定的一个原子数据,并且不能进一步地被分解为更小的可以独立修改的数据。

jsonb容器

测试容器jsonb的一项重要功能。 json类型没有并行的设施集。容器测试一个jsonb 文档中是否包含了另一个jsonb文档。这些示例返回true,除非另有标注:

--简单标量/原始数值仅包含相同的值:
SELECT '"foo"'::jsonb @> '"foo"'::jsonb;

-- 右边的数组包含在左边的数组中:
SELECT '[1, 2, 3]'::jsonb @> '[1, 3]'::jsonb;

--数组元素的顺序并不重要,因此这也是正确的:
SELECT '[1, 2, 3]'::jsonb @> '[3, 1]'::jsonb;

-- 重复的数组元素也不重要:
SELECT '[1, 2, 3]'::jsonb @> '[1, 2, 2]'::jsonb;

-- 右侧只有一对的对象包含在左侧的对象中:
SELECT '{"product": "SeaboxMPP", "version": "6.0.0", "jsonb":true}'::jsonb @> '{"version":"6.0.0"}'::jsonb;

--右侧的数组被认为不包含在左侧的数组中,即使其中嵌套了类似的数组:
SELECT '[1, 2, [1, 3]]'::jsonb @> '[1, 3]'::jsonb;  -- yields false

--但是,通过一层嵌套,它包含:
SELECT '[1, 2, [1, 3]]'::jsonb @> '[[1, 3]]'::jsonb;

--同样,此处未报告遏制:
SELECT '{"foo": {"bar": "baz", "zig": "zag"}}'::jsonb @> '{"bar": "baz"}'::jsonb; -- yields false

-- 但是,通过一层嵌套,它包含:
SELECT '{"foo": {"bar": "baz", "zig": "zag"}}'::jsonb @> '{"foo": {"bar": "baz"}}'::jsonb;

一般原则是,所包含的对象必须在结构和数据内容方面与包含的对象匹配,可能是在从包含的对象中丢弃一些不匹配的数组元素或对象键/值对之后。 对于容器,在进行容器匹配时,数组元素的顺序并不重要,重复的数组元素只被有效地考虑一次。

作为结构必须匹配的一般原则的例外,数组可以包含原始值:

-- 此数组包含原始字符串值::
SELECT '["foo", "bar"]'::jsonb @> '"bar"'::jsonb;

-- 这个异常不是相互的——这里报告了非包容::
SELECT '"bar"'::jsonb @> '["bar"]'::jsonb;  -- yields false

jsonb还有一个扩展操作符,它是容器主题的变体:它测试字符串(作为文本值给出)是否作为对象键或数组元素出现在jsonb值的顶层。这些示例返回true,,除非另有标注:

-- 字符串作为数组元素存在:
SELECT '["foo", "bar", "baz"]'::jsonb ? 'bar';

-- 字符串作为对象键存在:
SELECT '{"foo": "bar"}'::jsonb ? 'foo';

-- 不考虑对象值:
SELECT '{"foo": "bar"}'::jsonb ? 'bar';  -- yields false

-- 与容器一样,存在必须在顶层匹配:
SELECT '{"foo": {"bar": "baz"}}'::jsonb ? 'bar'; -- yields false

-- 如果字符串与原始JSON字符串匹配,则认为该字符串存在:
SELECT '"foo"'::jsonb ? 'foo';

当涉及到许多键或元素时,JSON对象比数组更适合测试包含性或存在性,因为与数组不同,JSON对象在内部针对搜索进行了优化,不需要进行线性搜索。

各种容器和存在操作符以及所有其他JSON操作符和函数都记录在JSON函数和操作符JSON函数和操作符中。

因为JSON容器是嵌套的,所以适当的查询可以跳过子对象的显式选择。例如,假设我们有一个包含顶级对象的doc列,其中大多数对象包含子对象数组的标记字段。此查询查找包含"term":"paris""term":"food"的子对象出现的条目,同时忽略标记数组之外的任何此类键:

SELECT doc->'site_name' FROM websites
  WHERE doc @> '{"tags":[{"term":"paris"}, {"term":"food"}]}';

使用这个谓词的查询可以完成相同的事情。

SELECT doc->'site_name' FROM websites
  WHERE doc->'tags' @> '[{"term":"paris"}, {"term":"food"}]';

然而,第二种方法的灵活性较低,而且效率通常也较低。

另一方面,json存在操作符不是嵌套的:它只在json值的顶层查找指定的键或数组元素。

jsonb数据GIN索引

可以使用GIN索引有效地搜索出现在大量jsonb文档(基准)中的键或键/值对。两个GIN操作符类,提供不同的性能和灵活性权衡。

jsonb的默认GIN操作符类支持带@>, ?, ?&?|操作符的查询。

CREATE INDEX idxgin ON api USING gin (jdoc);

非默认的GIN运算符类jsonb_path_ops仅支持为@>运算符编制索引。使用此运算符类创建索引的示例如下:

CREATE INDEX idxginp ON api USING gin (jdoc jsonb_path_ops);

考虑一个表的示例,该表存储从第三方Web服务检索到的JSON文档,并且具有文档化的模式定义。这是一个典型的文档:

{
    "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"
    ]
}

JSON文档存储在jsonb列中的一个名为API的表中。如果在此列上创建了GIN索引,则以下查询可以使用该索引:

-- 查找关键词“公司”具有“magnafone”价值的文档:
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @> '{"company": "Magnafone"}';

但是,索引不能用于以下查询。操作符? 是可索引的,但是,比较不会直接应用于索引列jdoc:

-- Find documents in which the key "tags" contains key or array element "qui"
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc -> 'tags' ? 'qui';

通过适当地使用表达式索引,上述查询可以使用索引。如果在tags 键中查询特定项是常见的,那么定义这样的索引可能是值得的:

CREATE INDEX idxgintags ON api USING gin ((jdoc -> 'tags'));

现在,WHERE子句 jdoc -> 'tags' ? 'qui'被认为是可索引运算符的应用? 到索引表达式jdoc -> 'tags'。有关表达式索引的信息,请参阅表达式索引表达式索引

查询JSON文档的另一种方法是利用包含性,例如:

-- 查找键“tags”包含数组元素"qui"的文档
            SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @> '{"tags": ["qui"]}';

jdoc列上的一个简单的GIN索引可以支持这个查询。但是,索引将在jdoc列中存储每个键和值的副本,而前一个示例的表达式索引只存储标记键下的数据。虽然简单索引方法要灵活得多(因为它支持关于任何键的查询),但是目标表达式索引可能比简单索引更小,搜索速度更快。

尽管 jsonb_path_ops类只支持带@>运算符的查询,但它比默认的jsonb_operator类具有性能优势。对于相同的数据,jsonb_path_ops索引通常比jsonb_ops索引小得多,搜索的特殊性更好,尤其是当查询包含频繁出现在数据中的键时。因此,搜索操作通常比默认的operator类执行得更好。

jsonb_opsjsonb-path-ops-gin索引的技术区别在于前者为数据中的每个键和值创建独立的索引项,而后者仅为数据中的每个值创建索引项。

注意:对于这个讨论,术语value包括数组元素,尽管JSON术语有时考虑数组元素不同于对象中的值。

基本上,每个jsonb_path_ops索引项都是值的散列和指向该值的键;例如,要索引{"foo": {"bar":"baz"}},将创建一个索引项,将foo, bar, 和baz中的三个都合并到散列值中。因此,查找此结构的包含查询将导致极其具体的索引搜索;但根本无法确定foo是否显示为键。另一方面,jsonb_ops索引将分别创建三个表示foo, bar, 和baz的索引项;然后,为了执行包含性查询,它将查找包含这三个项的行。虽然GIN索引可以相当有效地执行这样的搜索,但是它仍然比同等的jsonb_path_ops搜索更不具体和更慢,特别是如果有大量的行包含三个索引项中的任何一个。

jsonb_path_ops方法的一个缺点是它不会为不包含任何值的json结构生成索引项,例如{"a":{}}:。如果请求搜索包含此类结构的文档,则需要进行完全索引扫描,这非常慢。jsonb_path_ops不适合经常执行这种搜索的应用程序。

jsonb数据btree索引和哈希索引

jsonb还支持btreehash索引。只有在检查完整JSON文档的相等性很重要时,这些方法才有用。

为完整起见,josonb 基准的btree 排序是:

Object > Array > Boolean > Number > String > Null

Object with n pairs > object with n - 1 pairs

Array with n elements > array with n - 1 elements

相等键值数的对象按以下顺序进行比较:

key-1, value-1, key-2 ...

对象键按存储顺序进行比较。特别是,由于较短的键存储在较长的键之前,这可能导致顺序不直观,例如:

{ "aa": 1, "c": 1} > {"b": 1, "d": 1}

同样,元素数目相等的数组按以下顺序进行比较:

element-1, element-2 ...

使用与底层SeaboxMPP数据库数据类型相同的比较规则来比较原始JSON值。使用默认数据库排序规则比较字符串。

JSON操作符

这个表格描述了可以用于jsonjsonb 数据类型的操作符。

jsonjsonb 操作符

操作符 右操作数类型 描述 示例 示例结果
-> int 获得JSON数组元素(索引从零开始)。 '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json->2 {"c":"baz"}
-> text 根据键获得JSON对象的域。 '{"a": {"b":"foo"}}'::json->'a' {"b":"foo"}
->> int 获得JSON数组元素的text形式。 '[1,2,3]'::json->>2 3
->> text 获得JSON对象域的text形式。 '{"a":1,"b":2}'::json->>'b' 2
#> text[] 获得在指定路径上的JSON对象。 '{"a": {"b":{"c": "foo"}}}'::json#>'{a,b}' {"c": "foo"}
#>> text[] 获得在指定路径上的JSON对象的text形式。 '{"a":[1,2,3],"b":[4,5,6]}'::json#>>'{a,2}' 3

注意: 对于jsonjsonb数据类型,这些运算符都有并行变体。字段、元素和路径提取运算符返回的数据类型与其左侧输入(jsonjsonb)相同,但指定为返回text的数据类型除外,后者将值强制为text。如果JSON输入没有与请求匹配的正确结构,则字段、元素和路径提取运算符返回NULL,而不是失败;例如,如果不存在这样的元素。

下表描述了需要jsonb数据类型作为左操作数的运算符。这些运算符中的许多都可以通过jsonb运算符类进行索引。有关jsonb包含和存在语义的完整描述,请参见jsonb容器与存在。有关如何使用这些运算符有效地索引JSONB数据的信息,请参阅jsonb索引

jsonb操作符

操作符 右操作数类型 描述 示例
@> jsonb 左边的json值包含右边的值吗? '{"a":1, "b":2}'::jsonb @> '{"b":2}'::jsonb
<@ jsonb 左JSON值是否包含在右值中? '{"b":2}'::jsonb <@ '{"a":1, "b":2}'::jsonb
? text 键/元素字符串是否存在于JSON值中? '{"a":1, "b":2}'::jsonb ? 'b'
?\| text[] 是否存在这些键/元素字符串? '{"a":1, "b":2, "c":3}'::jsonb ?\| array['b', 'c']
?& text[] 所有这些键/元素字符串都存在吗? '["a", "b"]'::jsonb ?& array['a', 'b']

下表中的标准比较运算符仅适用于 jsonb数据类型,而不适用于 json数据类型。它们遵循jsonb索引jsonb索引中描述的B树操作的排序规则。

jsonb 比较运算符

操作符 描述
< 小于
> 大于
<= 小于或等于
>= 大于或等于
= 等于
<>或者!= 不等于

注意: 这个!=运算符在解析阶段转换为 <>。无法执行!=<>来执行不同操作的运算符。

JSON创建函数

此表描述了创建 json数据类型值的函数。(目前, jsonb没有等价的函数,但是您可以将其中一个函数的结果强制转换为jsonb。)

  • to_json(anyelement)
描述
返回该值作为一个合法的JSON对象。 数组和组合会被递归处理并且转换成数组和对象。如果输入包含一个从该类型到 json的转换,会使用该cast函数来执行转换,否则将会产生一个JSON标量值。对于任何非数字、布尔值或空值的标量类型,会使用其文本表示,并且加上适当的引号和转义让它变成一个合法的JSON字符串。
示例
to_json('Fred said "Hi."'::text)
示例结果
"Fred said \"Hi.\""
  • array_to_json(anyarray [, pretty_bool])
描述
返回该数组为一个JSON数组。一个SeaboxMPP数据库多维数组会变成一个JSON数组的数组。 如果pretty_bool 为true,在第一维元素之间会增加换行。
示例
array_to_json('{{1,5},{99,100}}'::int[])<
示例结果
[1,5],[99,100]
  • row_to_json(record [, pretty_bool])
描述
返回该行为一个JSON对象。如果pretty_bool pretty_bool为true,在第一级别元素之间会增加换行。
示例
row_to_json(row(1,'foo'))
示例结果
{"f1":1,"f2":"foo"}
  • json_build_array(VARIADIC "any")
描述
从VARIADIC 参数列表构建一个可能是异种类型的JSON数组。
示例
json_build_array(1,2,'3',4,5)
示例结果
[1, 2, "3", 4, 5]
  • json_build_object(VARIADIC "any")
描述
从VARIADIC参数列表构建JSON对象。参数列表按顺序获取,并转换为一组键/值对。
示例
json_build_object('foo',1,'bar',2)
示例结果
{"foo": 1, "bar": 2}
  • json_object(text[])
描述
从文本数组构建JSON对象。数组必须是一维或二维数组。一维数组必须有偶数个元素。元素作为键/值对。对于二维数组,每个内部数组必须恰好有两个元素,作为键/值对。
示例

json_object('{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对象。这一形式的json_object对象从两个分隔阵列中选择了键和值对。在所有其他方面,它与一个论据形式相同。
示例
json_object('{a, b}', '{1,2}')
示例结果
{"a": "1", "b": "2"}

注意: array_to_jsonrow_to_json的行为与to_json相同,只是提供了一个打印漂亮的选项。to_json描述的行为同样适用于其他JSON创建函数转换的每个单独的值。

注意:hstore模块包含从hstore转换为json的函数,因此通过json创建函数转换的hstore`值将被表示为json对象,而不是原始字符串值。

JSON聚合函数

此表显示函数将记录聚合到一个JSON对象数组和一对JSON对象的值。

表 JSON聚合函数

函数 参数类型 返回类型 描述
json_agg(record) record json 将记录聚合为对象的JSON数组。
json_object_agg(name, value) ("any", "any") json 将名称/值对聚合为JSON对象。
JSON处理函数

这个表描述处理jsonjsonb值的函数。

许多处理函数和运算符将JSON字符串中的Unicode转义符转换为适当的单个字符。如果输入数据类型是jsonb,这不是问题,因为转换已经完成。但是,对于json数据类型输入,这可能导致抛出错误。请参见关于 关于JSON数据

  • json_array_length(json),jsonb_array_length(jsonb)
返回类型
int
描述
返回最外层JSON数组中的元素数。
示例
json_array_length('[1,2,3,{"f1":1,"f2":[5,6]},4]')
示例结果
5
  • json_each(json),jsonb_each(jsonb)
返回类型

setof key text, value json

setof key text, value jsonb

描述
将最外层的JSON对象展开为一组键/值对。
示例
select * from json_each('{"a":"foo", "b":"bar"}')

示例结果

 key | value
-----+-------
 a   | &quot;foo&quot;
 b   | &quot;bar&quot;</code></pre></td>

  • json_each_text(json),jsonb_each_text(jsonb)
返回类型
setof key text, value text
描述
把最外层的JSON对象展开成键/值对的集合。返回值的类型是text。
示例
select * from json_each_text('{"a":"foo", "b":"bar"}')

示例结果

key | value -----+------- a | foo b | bar

  • json_extract_path()
用法
json_extract_path(from_json json, VARIADIC path_elems text[]),jsonb_extract_path(from_json jsonb, VARIADIC path_elems text[])
返回类型
json,jsonb
描述
返回path_elems指定的JSON值。等效于#>操作符。
示例
json_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}','f4')
示例结果
{"f5":99,"f6":"foo"}
  • json_extract_path_text(from_json json, VARIADIC path_elems text[]),jsonb_extract_path_text(from_json jsonb, VARIADIC path_elems text[])
返回类型
text
描述
以文本形式返回path_elems指向的JSON值。相当于>>运算符。
示例
json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}','f4','f6')
示例结果
foo
  • json_object_keys(json),jsonb_object_keys(jsonb)
返回类型
setof text
描述
返回最外层JSON对象中的键集合。
示例
json_object_keys('{"f1":"abc","f2":{"f3":"a", "f4":"b"}}')
示例结果
``` json_object_keys
f1 f2 ```
  • json_populate_record(base anyelement, from_json json), jsonb_populate_record(base anyelement, from_json jsonb)
返回类型
anyelement
描述
把from_json的对象展开成一行,其中的列匹配由base定义的记录类型。
示例
select * from json_populate_record(null::myrowtype,'{"a":1,"b":2}')
示例结果
a | b ---+--- 1 | 2
  • json_populate_recordset(base anyelement, from_json json), jsonb_populate_recordset(base anyelement, from_json jsonb)
返回类型
setof anyelement
描述
将from_json的最外层数组从json扩展到一组行,这些行的列与基定义的记录类型匹配。
示例
select * from json_populate_recordset(null::myrowtype, '[{"a":1,"b":2},{"a":3,"b":4}]')
示例结果
a | b ---+--- 1 | 2 3 | 4
  • json_array_elements(json),jsonb_array_elements(jsonb)
返回类型
setof json,setof jsonb
描述
将JSON数组扩展为一组JSON值。
示例
select * from json_array_elements('[1,true, [2,false]]')
示例结果
``` value
1 true [2,false] ```
  • json_array_elements_text(json),jsonb_array_elements_text(jsonb)
返回类型
setof text
描述
将JSON数组扩展为一组文本值。
示例
select * from json_array_elements_text('["foo", "bar"]')
示例结果
``` value
foo bar ```
  • json_typeof(json),jsonb_typeof(jsonb)
返回类型
text
描述
以文本字符串形式返回最外面的JSON值的类型。可能的类型包括object, array, string, number, boolean, 和 null。
示例
json_typeof('-123.4')
示例结果
number
  • json_to_record(json),jsonb_to_record(jsonb)
返回类型
record
描述
从JSON对象生成任意记录,与所有返回记录的函数一样,调用方必须使用AS子句显式定义记录的结构。
示例
select * from json_to_record('{"a":1,"b":[1,2,3],"c":"bar"}') as x(a int, b text, d text)
示例结果
a | b | d ---+---------+--- 1 | [1,2,3] |</code></pre></td>
  • json_to_recordset(json),jsonb_to_recordset(jsonb)
返回类型
setof record
描述
从JSON对象数组生成任意记录集,与所有返回记录的函数一样,调用方必须使用AS clause子句显式定义记录的结构。
示例
select * from json_to_recordset('[{"a":1,"b":"foo"},{"a":"2","c":"bar"}]') as x(a int, b text);
示例结果
a | b ---+----- 1 | foo 2 |

注意:

  1. 函数json_populate_record(),json_populate_recordset(), json_to_record()json_to_recordset()的示例使用常量。

    但是,典型的用法是引用FROM子句中的表,并使用它的jsonjsonb列之一作为函数的参数。然后可以在查询的其他部分中引用提取的键值。例如,可以在WHERE子句和目标列表中引用该值。以这种方式提取多个值可以提高性能,而不是使用每个键操作符分别提取多个值。

    JSON键与目标行类型中相同的列名匹配。这些函数的JSON类型强制可能不会产生某些类型所需的值。目标行类型中未出现的JSON字段将从输出中省略,不匹配任何JSON字段的目标列将为空。

  2. json_typeof函数NULL返回值

    null不应与SQLNULL混淆。当调用json_typeof('null'::json)将返回null时,调用json_typeof(NULL::json)将返回SQLNULL