MySQL支持根据符合JSON模式规范Draft 4的JSON模式验证JSON文档。这可以使用本节中详细介绍的两个函数来实现,两个函数都需要两个参数:一个JSON模式和一个要验证的JSON文档。JSON_SCHEMA_VALID()
如果文档验证通过模式则返回true,否则返回false;JSON_SCHEMA_VALIDATION_REPORT()
提供了验证报告的JSON格式。
这两个函数处理空或无效输入如下:
-
如果至少有一个参数是
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
。两个schema
和document
都是必需的。模式必须是一个有效的JSON对象;文档必须是一个有效的JSON文档。只要满足这些条件:如果文档验证通过模式,则函数返回true(1);否则,返回false(0)。在这个示例中,我们将用户变量
@schema
设置为地理坐标的JSON模式的值,并将另一个用户变量@document
设置为包含一个坐标的JSON文档的值。然后,我们使用它们作为JSON_SCHEMA_VALID()
的参数来验证@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
,表示地图上的点的经纬度,由JSON模式作为JSON_SCHEMA_VALID()
调用的参数,作为该表的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_SCHEMA_VALID()
指定约束时将JSON模式内联传递。我们将三个变量分配给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)
请参阅 第 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 文档。如果 JSON 文档根据 JSON Schema 有效,则函数返回一个 JSON 对象,其中包含一个名为valid
的属性,值为 "true"。如果 JSON 文档验证失败,则函数返回一个 JSON 对象,其中包括以下属性:-
valid
:失败的 schema 验证总是 "false" -
reason
:一个人类可读的字符串,包含失败的原因 -
schema-location
:一个 JSON 指针 URI 片段标识符,指示 JSON schema 中的验证失败位置(见下面的注释) -
document-location
:一个 JSON 指针 URI 片段标识符,指示 JSON 文档中的验证失败位置(见下面的注释) -
schema-failed-keyword
:一个字符串,包含 JSON schema 中违反的关键字或属性
NoteJSON 指针 URI 片段标识符定义在 RFC 6901 - JavaScript Object Notation (JSON) Pointer 中。(这些与 MySQL JSON 函数使用的 JSON 路径符号不同,例如
JSON_EXTRACT()
。)在这种符号中,#
代表整个文档,而#/myprop
代表文档中名为myprop
的顶级属性的部分。请参阅相关规范和后面的示例,以获取更多信息。在这个示例中,我们将用户变量
@schema
设置为地理坐标的 JSON schema 的值,并将另一个用户变量@document
设置为包含一个坐标的 JSON 文档的值。然后,我们使用这两个变量作为JSON_SCHEMA_VALIDATION_REPORT()
的参数来验证@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_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
设置为一个有效的值,但不包含必需的属性,然后将其与@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 schema,但没有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)
-