#json
JSON是一种独立于编程语言的数据交换格式,采用文本格式来表述数据,对于数据库系统,支持JSON格式可以使得应用和数据库之间传递数据变得更简洁、易懂和有结构逻辑。
YashanDB支持使用标准的JSON格式来定义和计算json数据,包括其两种结构形式和六种数据类型。
关于JSON的标准语法描述详见其官方网站ECMA-404 The JSON Data Interchange Standard (opens new window)。
# JSON的结构形式
键值对形式
这种结构的json数据是一组无序的"键(Key):值(Value)"的集合,该集合通过{
开始,以右括号}
结束,多个"键(Key):值(Value)"之间使用,
分割。如下所示:
{
"key1": "abc",
"key2": 123,
"key3": true,
"key4": null
}
数组形式
这种结构的json数据是一组有序的值(Value)的集合,该集合通过[
开始,以]
结束,Value之间使用逗号,
分割。如下所示:
[
"ghi",
789
]
多结构嵌套混合
一个json数据可以由多个结构形式嵌套混合组成,以满足各种业务数据组织要求。如下所示:
{
"key1": "abc",
"key2": 123,
"key3": true,
"key4": null,
"key5": [
"def",
456,
false,
null,
[
"ghi",
789
],
{
"key": "value"
}
],
"key6": {
"key": "value"
}
}
# JSON的数据类型
根据标准JSON格式定义,json数据里的Value可以为如下类型:
- 对象(Object)
- 数组(Array)
- 字符串(String)
- 数字(Number)
- 布尔值(True/False)
- 空值(Null)
其中:
1.对象(Object)和数组(Array)中的值(Value)可以为字符串(String)、数字(Number)、布尔值(True/False)、空值(Null)或者嵌套的对象(Object)和数组(Array)。
2.字符串(String)是由零个或者更多个Unicode字符组成的序列,前后使用双引号"
来标识,且支持使用反斜杠\
进行转义。
3.布尔值和空值必须采用全小写输入,即true/false/null。
# 路径表达式
YashanDB提供了一些内置函数实现对一个json数据内部的搜索查找功能(例如检索某个Key是否存在于某个json数据中),这需要结合路径表达式(Path Expression)一起使用。
路径表达式有点类似于XML数据的XQuery或XPath表达式,其语法定义如下:
json_path::=
object_step::=
array_step::=
item_method::=
路径表达式使用绝对路径,以符号$
开始,其含义用于表述检索json数据时的匹配路径。$
后面跟着零个或者多个nonfunction_steps,以及一个可选的function_step,即支持多步骤匹配;不跟任何内容时,表示与json数据完全一致的匹配路径。
一个路径表达式会选择零个或者多个匹配的值。一般情况下,路径表达式会依次尝试匹配路径表达式中的每一个步骤。如果当前步骤匹配失败,则不会尝试匹配后续步骤,并且路径表达式匹配失败。如果每一个步骤都匹配成功,则路径表达式匹配成功。
其中路径表达式中的key在无双引号的情况下只允许字母数字,不允许任何其余字符出现,需要使用特殊字符时需要按标准json string语法在字符串的前后加上双引号。
示例
SELECT JSON_QUERY(JSON('{"1":1,"2":2,"3":3}'), '$') res FROM dual;
RES
----------------------------------------------------------------
{"1":1,"2":2,"3":3}
# nonfunction_steps
非函数类匹配步骤,可以为object_step、array_step或者descendent_step中的某一个。
# object_step
针对键值对结构的json数据的匹配步骤,以.
开始,后面跟着一个Key或者一个通配符*
。
Key如果不使用双引号标识时,必须以大写或者小写字母a-z开头,且只能包含字母或者十进制数字(0-9),否则必须使用双引号进行标识。
Key可以为空,如果为空,则必须写成""
的形式。
使用object_step匹配时,系统将按指定的Key检索json数据,并返回Key对应的Value。指定通配符时,返回所有的Value。
示例
SELECT JSON_QUERY(JSON('{"1":1,"2":2,"3":3}'), '$.*' WITH WRAPPER) res FROM dual;
RES
----------------------------------------------------------------
[1,2,3]
SELECT JSON_QUERY(JSON('{"1":1,"2":2,"3":3}'), '$.""') res FROM dual;
RES
----------------------------------------------------------------
SELECT JSON_QUERY(JSON('{"1":1,"2":2,"3":3}'), '$."1"') res FROM dual;
RES
----------------------------------------------------------------
1
# array_step
针对数组结构的json数据的匹配步骤,以[
开始,以]
结束,不允许出现空的[],[]中间的内容形式可以为:
- 通配符
*
:匹配所有Value。 - 数组索引位置array_index:按Value在数组中的位置匹配,可以同时指定多个位置匹配,以
,
分隔。数组位置为从0开始的整数,即数组的第一个元素的索引为0。也可以是last - N
的形式,表示从数组尾部开始查找,例如last - 1表示索引数组中倒数第二个元素。单独的last
等价于last - 0
,表示索引数组中最后一个元素。 - 数组索引范围array_n "to" array_m:其形式为
N to M
,N和M都是位置索引,按Value在数组中的位置范围进行匹配,等价于显式地指定从N到M的所有索引位置,例如[2 to 4]等价于[2, 3, 4]。其中N和M的大小顺序没有特殊要求,例如,表示第三到第六个元素的索引范围可以是[2 to 5],也可以是[5 to 2]。需要注意的是[N to N]
等价于[N]
而不是[N, N]
。
使用array_step匹配时,上述三种形式必须至少出现一个,但是通配符只能独立出现。
当数组索引位置和数组索引范围可以出现多个,当多个索引位置存在重叠时,重叠区域中的元素会被多次匹配到。
如果指定的索引位置或者索引范围超过了数组本身的范围,则系统将认为没有匹配到数据,而不会报错。
示例
SELECT JSON_QUERY(JSON('[1,2,3,4,5,6,7,8,9]'), '$[0 to 2, 5 to 3, last to last - 2, 1, 1]' WITH WRAPPER) res FROM dual;
RES
----------------------------------------------------------------
[1,2,3,4,5,6,7,8,9,2,2]
# descendent_step
针对键值对结构的json数据的递归匹配步骤,以两个连续的句号..
开始,后面跟着一个Key。它基于当前步骤之前匹配到的数据,进行递归查找,返回所有匹配到的值。
示例
SELECT JSON_QUERY(JSON('{ "a" : { "b" : { "d" : 1 },
"c" : [ 2, { "d" : 3 } ],
"d" : 4 },
"d" : 5 }'), '$.a..d' WITH WRAPPER) res FROM dual;
RES
----------------------------------------------------------------
[4,1,3]
# function_step
函数类匹配步骤,function_step在路径表达式中不是必须出现的,如果出现,它只能是路径表达式的最后一步。function_step以.
开始,后面跟着函数方法名称,及左右括号()
,括号之间可以有空格。
# item_method
函数方法名称,函数方法应用于当前步骤之前匹配到的数据,对其进行数据转换,包括如下几种:
- count:返回当前步骤之前匹配到的数据的数量。
- size:如果当前步骤之前匹配到的数据为数组,返回数组的元素数量,如果不是数组,返回NULL。
- type:返回当前步骤之前匹配到的数据的类型。
示例
SELECT JSON_QUERY(JSON('{ "a" : { "b" : { "d" : 1 },
"c" : [ 2, { "d" : 3 } ],
"d" : 4 },
"d" : 5 }'), '$.a..d.count()' WITH WRAPPER) res FROM dual;
RES
----------------------------------------------------------------
[3]
# 宽松匹配
在严格匹配的模式下,根据路径表达式对json数据进行检索时,路径表达式中的某个匹配步骤只能应用于特定的数据类型,具体要求为:
- object_step只能对Object类型数据进行查找,应用于其他类型均认为匹配失败。
- array_step只能对Array类型数据进行查找,应用于其他类型均认为匹配失败。
为了提供更灵活的查询,YashanDB支持宽松匹配模式(系统默认为此种模式),具体规则为:
如果当前为array_step匹配,但json数据为非Array类型,则系统自动将json数据封装为长度为1的数组,然后进行匹配。
示例
SELECT JSON_QUERY(JSON('1'), '$[0]') res FROM dual; RES ---------------------------------------------------------------- 1
如果当前为非array_step匹配,如object_step、function_step等,但json数据为Array类型,则系统对Array中的每个元素应用当前的匹配路径。
示例
SELECT JSON_QUERY(JSON('[{"a": 1}, {"a": 2}, {"a": 3}]'), '$.a' WITH WRAPPER) res FROM dual; RES ---------------------------------------------------------------- [1,2,3]