14.17.7 JSON 模式验证函数
MySQL 支持根据 JSON 模式对 JSON 文档进行验证,该模式遵循JSON 模式规范的第四稿。可以使用本节中详细介绍的两个函数之一,两个函数都接受两个参数:一个 JSON 模式和要对其进行验证的 JSON 文档。JSON_SCHEMA_VALID()
如果文档符合模式,则返回 true;否则返回 false;JSON_SCHEMA_VALIDATION_REPORT()
提供了对验证结果的报告,该报告以 JSON 格式。
两个函数处理 null 或无效输入如下:
-
如果至少有一个参数为
NULL
,函数返回NULL
。 -
如果至少有一个参数不是有效的 JSON,则函数抛出错误(
ER_INVALID_TYPE_FOR_JSON
) -
此外,如果模式不是有效的 JSON 对象,则函数返回
ER_INVALID_JSON_TYPE
。
MySQL 支持在 JSON 模式中使用 required
属性来强制包含必需的属性(请参阅函数描述中的示例)。
MySQL 支持 JSON 模式中的 id
、$schema
、description
和 type
属性,但不需要任何这些属性。
MySQL 不支持 JSON 模式中的外部资源;使用 $ref
关键字将导致 JSON_SCHEMA_VALID()
失败,返回ER_NOT_SUPPORTED_YET
。
MySQL 支持 JSON 模式中的正则表达式模式,支持但忽略无效的模式(请参阅 JSON_SCHEMA_VALID()
的描述以获取示例)。
这些函数在以下列表中有详细描述:
-
JSON_ SCHEMA_VALID(
schema
,document
)验证 JSON
document
对 JSONschema
。 bothschema
和document
都是必需的。schema 必须是一个有效的 JSON 对象;document 必须是一个有效的 JSON 文档。如果文档验证通过 schema,函数返回 true(1);否则,返回 false(0)。在这个示例中,我们将用户变量
@schema
设置为一个用于地理坐标的 JSON 模式,并将另一个变量@document
设置为包含一个这样的坐标的 JSON 文档。然后,我们使用它们作为参数来验证@document
是否符合@schema
,如下所示:mysql> SET @schema = '{ '> "id": "http://json-schema.org/geo", '> "$schema": "http://json-schema.org/draft-04/schema#", '> "description": "A geographical coordinate", '> "type": "object", '> "properties": { '> "latitude": { '> "type": "number", '> "minimum": -90, '> "maximum": 90 '> }, '> "longitude": { '> "type": "number", '> "minimum": -180, '> "maximum": 180 '> } '> }, '> "required": ["latitude", "longitude"] '>}'; Query OK, 0 rows affected (0.01 sec) mysql> SET @document = '{ '> "latitude": 63.444697, '> "longitude": 10.445118 '>}'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT JSON_SCHEMA_VALID(@schema, @document); +---------------------------------------+ | JSON_SCHEMA_VALID(@schema, @document) | +---------------------------------------+ | 1 | +---------------------------------------+ 1 row in set (0.00 sec)
由于
@schema
包含了required
属性,我们可以将@document
设置为一个有效的值,但不包含必需的属性,然后测试它对@schema
,如下所示:mysql> SET @document = '{}'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT JSON_SCHEMA_VALID(@schema, @document); +---------------------------------------+ | JSON_SCHEMA_VALID(@schema, @document) | +---------------------------------------+ | 0 | +---------------------------------------+ 1 row in set (0.00 sec)
现在,如果我们将
@schema
的值设置为同一个 JSON 模式,但没有required
属性,@document
将验证,因为它是一个有效的 JSON 对象,即使它不包含任何属性,如下所示:mysql> SET @schema = '{ '> "id": "http://json-schema.org/geo", '> "$schema": "http://json-schema.org/draft-04/schema#", '> "description": "A geographical coordinate", '> "type": "object", '> "properties": { '> "latitude": { '> "type": "number", '> "minimum": -90, '> "maximum": 90 '> }, '> "longitude": { '> "type": "number", '> "minimum": -180, '> "maximum": 180 '> } '> } '>}'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT JSON_SCHEMA_VALID(@schema, @document); +---------------------------------------+ | JSON_SCHEMA_VALID(@schema, @document) | +---------------------------------------+ | 1 | +---------------------------------------+ 1 row in set (0.00 sec)
JSON_SCHEMA_VALID() 和 CHECK 约束.
JSON_SCHEMA_VALID()
也可以用来强制CHECK
约束。考虑创建的表
geo
,其中包含一个 JSON 列coordinate
,表示地图上的 latitude 和 longitude 点,该列由在JSON_SCHEMA_VALID()
调用的 JSON 模式作为参数来控制的 CHECK 约束:mysql> CREATE TABLE geo ( -> coordinate JSON, -> CHECK( -> JSON_SCHEMA_VALID( -> '{ '> "type":"object", '> "properties":{ '> "latitude":{"type":"number", "minimum":-90, "maximum":90}, '> "longitude":{"type":"number", "minimum":-180, "maximum":180} '> }, '> "required": ["latitude", "longitude"] '> }', -> coordinate -> ) -> ) -> ); Query OK, 0 rows affected (0.45 sec)
Note由于 MySQL 的
CHECK
约束不能包含变量引用,因此您必须将 JSON 模式传递给JSON_SCHEMA_VALID()
以便在指定表的约束时使用它。我们将 JSON 值,表示坐标,分配给三个变量,如下所示:
mysql> SET @point1 = '{"latitude":59, "longitude":18}'; Query OK, 0 rows affected (0.00 sec) mysql> SET @point2 = '{"latitude":91, "longitude":0}'; Query OK, 0 rows affected (0.00 sec) mysql> SET @point3 = '{"longitude":120}'; Query OK, 0 rows affected (0.00 sec)
这些值中第一个是有效的,可以在以下
INSERT
语句中看到:mysql> INSERT INTO geo VALUES(@point1); Query OK, 1 row affected (0.05 sec)
第二个 JSON 值无效,因此违反约束,如下所示:
mysql> INSERT INTO geo VALUES(@point2); ERROR 3819 (HY000): Check constraint 'geo_chk_1' is violated.
您可以通过发出
SHOW WARNINGS
语句来获取关于失败的精确信息——在这个例子中,latitude 值超过了 schema 中定义的最大值:mysql> SHOW WARNINGS\G *************************** 1. row *************************** Level: Error Code: 3934 Message: The JSON document location '#/latitude' failed requirement 'maximum' at JSON Schema location '#/properties/latitude'. *************************** 2. row *************************** Level: Error Code: 3819 Message: Check constraint 'geo_chk_1' is violated. 2 rows in set (0.00 sec)
上述第三个坐标值也无效,因为它缺少必需的
latitude
属性。正如前面所示,您可以尝试将该值插入到geo
表中,然后发出SHOW WARNINGS
语句:mysql> INSERT INTO geo VALUES(@point3); ERROR 3819 (HY000): Check constraint 'geo_chk_1' is violated. mysql> SHOW WARNINGS\G *************************** 1. row *************************** Level: Error Code: 3934 Message: The JSON document location '#' failed requirement 'required' at JSON Schema location '#'. *************************** 2. row *************************** Level: Error Code: 3819 Message: Check constraint 'geo_chk_1' is violated. 2 rows in set (0.00 sec)
请参阅
Section 15.1.20.6, “CHECK 约束”
,了解更多信息。JSON Schema 支持指定字符串的正则表达式模式,但是 MySQL 的实现默默地忽略无效的模式。这意味着
JSON_SCHEMA_VALID()
可以返回 true,即使正则表达式模式无效,如下所示:mysql> SELECT JSON_SCHEMA_VALID('{"type":"string","pattern":"("}', '"abc"'); +---------------------------------------------------------------+ | JSON_SCHEMA_VALID('{"type":"string","pattern":"("}', '"abc"') | +---------------------------------------------------------------+ | 1 | +---------------------------------------------------------------+ 1 row in set (0.04 sec)
-
JSON_SCHEMA_VALIDATION_REPORT(
schema
,document
)验证一个JSON
document
对应一个JSONschema
。两个schema
和document
都是必需的。与JSON_VALID_ SCHEMA()相同,schema必须是一个有效的JSON对象,document必须是一个有效的JSON文档。如果满足这些条件,该函数将返回一个验证结果报告作为一个JSON文档。如果根据JSON Schema认为JSON文档是有效的,该函数将返回一个JSON对象,其中包含一个名为valid
的属性,并且该值为“true”。如果JSON文档失败验证,该函数将返回一个JSON对象,其中包含以下属性:-
valid
: 对于失败的schema验证总是“false” -
reason
: 包含失败原因的可读人字符串 -
schema-location
: 指示JSON schema中验证失败的位置的JSON指针URI片段标识符(见以下注释) -
document-location
: 指示JSON文档中验证失败的位置的JSON指针URI片段标识符(见以下注释) -
schema-failed-keyword
: 包含在JSON schema中违反的关键字或属性名称的字符串
NoteJSON 指针 URI 片段标识符在 RFC 6901 - JavaScript Object Notation (JSON) Pointer 中定义。(这与 MySQL JSON 函数
JSON_EXTRACT()
和其他 MySQL JSON 函数使用的 JSON 路径 notation 不同。) 在这个notation中,#
表示整个文档,而#/myprop
表示文档中的顶级属性名为myprop
的部分。请参阅上述引用和本节后面的示例以获取更多信息。在这个示例中,我们将用户变量
@schema
设置为地理坐标的 JSON 模式,并将另一个变量@document
设置为包含一个这样的坐标的 JSON 文档。然后,我们使用它们作为参数来验证@document
是否符合@schema
,通过调用JSON_ SCHEMA_VALIDATION_REPORT()
:mysql> SET @schema = '{ '> "id": "http://json-schema.org/geo", '> "$schema": "http://json-schema.org/draft-04/schema#", '> "description": "A geographical coordinate", '> "type": "object", '> "properties": { '> "latitude": { '> "type": "number", '> "minimum": -90, '> "maximum": 90 '> }, '> "longitude": { '> "type": "number", '> "minimum": -180, '> "maximum": 180 '> } '> }, '> "required": ["latitude", "longitude"] '>}'; Query OK, 0 rows affected (0.01 sec) mysql> SET @document = '{ '> "latitude": 63.444697, '> "longitude": 10.445118 '>}'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT JSON_SCHEMA_VALIDATION_REPORT(@schema, @document); +---------------------------------------------------+ | JSON_SCHEMA_VALIDATION_REPORT(@schema, @document) | +---------------------------------------------------+ | {"valid": true} | +---------------------------------------------------+ 1 row in set (0.00 sec)
现在,我们将
@document
设置为其中一个属性的非法值,如下所示:mysql> SET @document = '{ '> "latitude": 63.444697, '> "longitude": 310.445118 '> }';
验证
@document
现在失败,当使用JSON_SCHEMA_VALIDATION_REPORT()
测试时。函数调用结果包含详细的失败信息(使用JSON_PRETTY()
将函数包围以提供更好的格式),如以下所示:mysql> SELECT JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema, @document))\G *************************** 1. row *************************** JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema, @document)): { "valid": false, "reason": "The JSON document location '#/longitude' failed requirement 'maximum' at JSON Schema location '#/properties/longitude'", "schema-location": "#/properties/longitude", "document-location": "#/longitude", "schema-failed-keyword": "maximum" } 1 row in set (0.00 sec)
由于
@schema
包含了required
属性,我们可以将@document
设置为一个有效的JSON对象,但不包含所需的属性,然后将其与@schema
进行测试。JSON_ SCHEMA_VALIDATION_REPORT()
的输出结果表明验证失败,因为缺少了所需的元素,如下所示:mysql> SET @document = '{}'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema, @document))\G *************************** 1. row *************************** JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema, @document)): { "valid": false, "reason": "The JSON document location '#' failed requirement 'required' at JSON Schema location '#'", "schema-location": "#", "document-location": "#", "schema-failed-keyword": "required" } 1 row in set (0.00 sec)
现在,如果我们将
@schema
的值设置为同一个JSON架构,但没有required
属性,@document
将被验证,因为它是一个有效的JSON对象,即使它不包含任何属性,如下所示:mysql> SET @schema = '{ '> "id": "http://json-schema.org/geo", '> "$schema": "http://json-schema.org/draft-04/schema#", '> "description": "A geographical coordinate", '> "type": "object", '> "properties": { '> "latitude": { '> "type": "number", '> "minimum": -90, '> "maximum": 90 '> }, '> "longitude": { '> "type": "number", '> "minimum": -180, '> "maximum": 180 '> } '> } '>}'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT JSON_SCHEMA_VALIDATION_REPORT(@schema, @document); +---------------------------------------------------+ | JSON_SCHEMA_VALIDATION_REPORT(@schema, @document) | +---------------------------------------------------+ | {"valid": true} | +---------------------------------------------------+ 1 row in set (0.00 sec)
-