JSON值的规范化、合并和自动包装

当一个字符串被解析并发现是一个有效的JSON文档时,它也会被规范化。这意味着,具有与稍后在文档中找到的键(从左到右)重复的键的成员将被丢弃。JSON_OBJECT()调用生成的对象值只包含第二个key1元素,因为该键名在之前值中出现过,如下所示:

在JSON列中插入值时也会执行规范化,如下所示:

这种"最后一次重复的键获胜"的行为是由RFC 7159建议的,并且已由大多数JavaScript解析器实现。(Bug #86866, Bug #26369555)

在MySQL 8.0.3之前的版本中,与文档中先前找到的key重复的key成员将被丢弃。以下JSON_OBJECT()调用生成的对象值不包括第二个key1元素,因为该键名在前面出现过:

在MySQL 8.0.3之前,在向JSON列中插入值时,也会执行"第一个重复键获胜"的规范化。

MySQL还会丢弃原始JSON文档中键、值或元素之间的多余空格,并在显示时在每个逗号(,)或冒号(:)后保留(或在必要时插入)一个空格。这样做是为了提高可读性。

产生JSON值的MySQL函数总是返回规范化的值。

为了提高查找效率,MySQL还对JSON对象的键进行排序。应该意识到,此排序的结果可能会发生更改,并且不能保证在不同版本之间保持一致。

合并JSON值

MySQL8.0.3(及更高版本)支持两种合并算法,由函数JSON_MERGE_PRESERVE()和JSON_MERGE_PATCH()实现。它们在处理重复键的方式上有所不同:JSON_MERGE_PRESERVE()保留重复键的值,而JSON_MERGE_PATCH()将丢弃除最后一个值之外的所有值。接下来的几段将解释这两个函数如何处理JSON文档的不同组合(即对象和数组)的合并。

JSON_MERGE_PRESERVE()与早期版本的MySQL(在MySQL 8.0.3中重命名)中的JSON_MERGE()函数相同。在MySQL8.0中,JSON_MERGE()仍然以JSON_MERGE_PRESERVE()别名被支持,但已弃用,并可能在将来的版本中删除。

合并数组 。在组合多个数组的上下文中,数组被合并成一个。JSON_MERGE_PRESERVE()通过将后面提及的数组连接到第一个数组的末尾来实现这一点。JSON_MERGE_PATCH()将每个参数视为一个由单个元素组成的数组(因此其索引为0),然后应用"最后一个重复键获胜"逻辑来仅选择最后一个参数。您可以比较此查询显示的结果:

多个对象合并后生成一个对象。JSON_MERGE_PRESERVE()把数组中具有相同键的对象各唯一值合并;然后将该数组用作结果中该键的值。JSON_MERGE_PATCH()从左到右丢弃找到重复键的值,这样结果只包含该键的最后一个值。以下查询说明了重复键a的结果差异:

在需要数组值的上下文中使用非数组值是会自动包装的:该值由[和]字符包围以将其转换为数组。在下面的语句中,每个参数都自动包装为一个数组([1],[2])。然后将这些值合并生成一个结果数组;与前两种情况一样,JSON_MERGE_PRESERVE()组合具有相同键的值,而JSON_MERGE_PATCH()将丢弃除最后一个外的所有重复键的值,如下所示:

数组和对象值的合并是通过将对象自动包装为一个数组,并通过合并值来合并数组,或者根据"最后的重复键获胜"原则(分别对应选择的合并函数是JSON_MERGE_PRESERVE()或JSON_MERGE_PATCH())合并数组,如本例所示:

搜索和修改JSON值

JSON路径表达式在JSON文档中选择一个值。

路径表达式指定操作文档位置,对于提取或修改JSON文档内容的函数非常有用。例如,以下查询从JSON文档中提取具有name键的成员的值:

路径语法使用前导的$字符来表示处理中的JSON文档,后面可以跟选择器(可选),这些选择器依次指示文档中更具体的部分:

●一个句点后跟一个键名,用给定的键命名对象中的成员。如果不带引号的键名称在路径表达式中不合法(例如,如果它包含空格),则必须用在双引号包含指定键名称。

● [N]附加到选择数组的路径后,表示在数组中位置N处的值。数组位置是以零开头的整数。如果路径未选择数组值,则路径[0]的计算结果与路径相同:

●[M to N]指定数组值的子集或范围,从位置M处的值开始,到位置N处的值结束。

支持用last作为最右边数组元素的索引的同义词。还支持数组元素的相对寻址。如果path没有选择数组值,path[last]的计算结果与path相同,如本节后面部分所示。

●路径可以包含*或**通配符:

■ .[*]计算JSON对象中所有成员的值。

■ [*]计算JSON数组中所有元素的值。

■ prefix**suffix计算以prefix开头、以suffix结束的所有路径。

● 文档中不存在的路径(计算结果为不存在的数据)计算结果为NULL。

让$引用包含三个元素的JSON数组:

● $[0]的计算结果为3。

● $[1]的计算结果为{"a": [5, 6], "b": 10}。

● $[2]的计算结果为[99, 100]。

● $[3]的计算结果为NULL(它引用第四个数组元素,它不存在)。

由于$[1]和$[2]的计算结果为非标量值,因此可以用更具体的路径表达式对它们选择嵌套的值。示例:

●$[1].a的计算结果为[5, 6]。

●$[1].a[1]的计算结果为6。

●$[1].b的值为10。

●$[2][0]的计算结果为99。

如前所述,如果未加引号的键名称在路径表达式中不合法,则必须用引号将键引起。让$来引用此值:

两个键都包含空格,必须用引号引用:

●$."a fish"的计算结果是shark。

●$."a bird"的计算结果是sparrow。

使用通配符的路径计算的数组可以包含多个值:

在以下示例中,路径$**.b计算为多个路径($.a.b和$.c.b),并生成匹配路径值的数组:

JSON数组区间 。可以使用带有to关键字的区间来指定JSON数组的子集。例如,$[1 to 3]包括数组的第二、第三和第四个元素,如下所示:

语法是 M to N,其中M和N分别是JSON数组中一系列元素的第一个和最后一个索引。N必须大于M;M必须大于或等于0。数组元素以0开头编制索引。

可以在支持通配符的上下文中使用区间。

官方文档地址: https://dev.mysql.com/doc/refman/8.0/en/json.html