路径

访问JSON文档中的特定元素

路径允许您访问JSON文档中的特定元素。由于不存在JSON路径语法的标准,Redis JSON实现了自己的语法。JSON的语法基于常见的最佳实践,并有意模仿JSONPath

JSON 支持两种查询语法:JSONPath 语法和第一版 JSON 中的旧路径语法

JSON 根据路径查询的第一个字符知道使用哪种语法。如果查询以字符 $ 开头,则使用 JSONPath 语法。否则,默认使用旧版路径语法。

返回的值是一个JSON字符串,其中包含一个顶层的JSON序列化字符串数组。 如果使用了多路径,则返回值是一个JSON字符串,其中包含一个顶层对象,该对象的值是序列化JSON值的数组。

JSONPath 支持

RedisJSON v2.0 引入了 JSONPath 支持。它遵循 Goessner 在他的 文章 中描述的语法。

JSONPath 查询可以解析 JSON 文档中的多个位置。在这种情况下,JSON 命令将操作应用于每个可能的位置。这是对 legacy path 查询的重大改进,后者仅对第一个路径进行操作。

请注意,使用JSONPath时,命令响应的结构通常会有所不同。有关更多详细信息,请参阅Commands页面。

新语法支持括号表示法,允许在键名中使用特殊字符,如冒号“:”或空格。

如果你想在CLI的查询中包含双引号,请将JSONPath用单引号括起来。例如:

JSON.GET store '$.inventory["mountain_bikes"]'

JSONPath 语法

以下JSONPath语法表改编自Goessner的路径语法比较

语法元素 描述
$ 根(最外层的JSON元素),开始路径。
. or [] 选择一个子元素。
.. 递归地遍历JSON文档。
* 通配符,返回所有元素。
[] 下标运算符,用于访问数组元素。
[,] 联合,选择多个元素。
[start:end:step] 数组切片,其中startendstep是索引值。你可以省略切片中的值(例如,[3:][:8:2])以使用默认值:start默认为第一个索引,end默认为最后一个索引,step默认为1。使用[*][:]来选择所有元素。
?() 过滤一个JSON对象或数组。支持比较运算符 (==, !=, <, <=, >, >=, =~),逻辑运算符 (&&, ||),以及括号 ((, ))
() 脚本表达式。
@ 当前元素,用于过滤器或脚本表达式。

JSONPath 示例

以下JSONPath示例使用此JSON文档,该文档存储了商店库存中物品的详细信息:

{
    "inventory": {
        "mountain_bikes": [
            {
                "id": "bike:1",
                "model": "Phoebe",
                "description": "This is a mid-travel trail slayer that is a fantastic daily driver or one bike quiver. The Shimano Claris 8-speed groupset gives plenty of gear range to tackle hills and there\u2019s room for mudguards and a rack too.  This is the bike for the rider who wants trail manners with low fuss ownership.",
                "price": 1920,
                "specs": {"material": "carbon", "weight": 13.1},
                "colors": ["black", "silver"],
            },
            {
                "id": "bike:2",
                "model": "Quaoar",
                "description": "Redesigned for the 2020 model year, this bike impressed our testers and is the best all-around trail bike we've ever tested. The Shimano gear system effectively does away with an external cassette, so is super low maintenance in terms of wear and tear. All in all it's an impressive package for the price, making it very competitive.",
                "price": 2072,
                "specs": {"material": "aluminium", "weight": 7.9},
                "colors": ["black", "white"],
            },
            {
                "id": "bike:3",
                "model": "Weywot",
                "description": "This bike gives kids aged six years and older a durable and uberlight mountain bike for their first experience on tracks and easy cruising through forests and fields. A set of powerful Shimano hydraulic disc brakes provide ample stopping ability. If you're after a budget option, this is one of the best bikes you could get.",
                "price": 3264,
                "specs": {"material": "alloy", "weight": 13.8},
            },
        ],
        "commuter_bikes": [
            {
                "id": "bike:4",
                "model": "Salacia",
                "description": "This bike is a great option for anyone who just wants a bike to get about on With a slick-shifting Claris gears from Shimano\u2019s, this is a bike which doesn\u2019t break the bank and delivers craved performance.  It\u2019s for the rider who wants both efficiency and capability.",
                "price": 1475,
                "specs": {"material": "aluminium", "weight": 16.6},
                "colors": ["black", "silver"],
            },
            {
                "id": "bike:5",
                "model": "Mimas",
                "description": "A real joy to ride, this bike got very high scores in last years Bike of the year report. The carefully crafted 50-34 tooth chainset and 11-32 tooth cassette give an easy-on-the-legs bottom gear for climbing, and the high-quality Vittoria Zaffiro tires give balance and grip.It includes a low-step frame , our memory foam seat, bump-resistant shocks and conveniently placed thumb throttle. Put it all together and you get a bike that helps redefine what can be done for this price.",
                "price": 3941,
                "specs": {"material": "alloy", "weight": 11.6},
            },
        ],
    }
}

首先,在您的数据库中创建JSON文档:

访问示例

以下示例使用JSON.GET命令从JSON文档中的各种路径检索数据。

您可以使用通配符操作符 * 来返回库存中所有项目的列表:

对于某些查询,多条路径可以产生相同的结果。例如,以下路径返回所有山地自行车的名称:

递归下降操作符 .. 可以从 JSON 文档的多个部分检索字段。以下示例返回所有库存物品的名称:

你可以使用数组切片从数组中选择一系列元素。这个例子返回前2辆山地自行车的名称:

过滤表达式 ?() 允许您根据特定条件选择 JSON 元素。您可以在这些表达式中使用比较运算符(==, !=, <, <=, >, >=,以及从版本 v2.4.2 开始,还包括 =~)、逻辑运算符(&&, ||)和括号((, ))。过滤表达式可以应用于数组或对象,遍历数组中的所有元素或对象中的所有,仅检索符合过滤条件的元素。

过滤器条件中的路径使用点符号,其中@表示当前数组元素或当前对象值,$表示顶级元素。例如,使用@.key_name来引用嵌套值,使用$.top_level_key_name来引用顶级值。

从版本v2.4.2开始,您可以使用比较运算符=~将左侧的字符串值的路径与右侧的正则表达式模式进行匹配。有关更多信息,请参阅支持的正则表达式语法文档

非字符串值不匹配。只有当左侧是字符串值的路径,右侧是硬编码字符串或字符串值的路径时,才会发生匹配。请参见下面的示例

正则表达式匹配是部分的,这意味着像 "foo" 这样的正则表达式模式会匹配像 "barefoots" 这样的字符串。 要使匹配精确,请使用正则表达式模式 "^foo$"

其他JSONPath引擎可能在斜杠之间使用正则表达式模式(例如,/foo/), 并且它们的匹配是精确的。它们可以使用正则表达式模式(如/.*foo.*/)执行部分匹配。

筛选示例

在以下示例中,过滤器仅返回价格低于3000且重量小于10的山地自行车:

此示例筛选出由合金制成的自行车型号的库存:

此示例从版本v2.4.2开始有效,仅过滤材料以"al-"开头的自行车,使用正则表达式匹配。请注意,由于正则表达式模式"(?i)al"中的前缀(?i),此匹配不区分大小写:

你也可以使用JSON对象本身的属性来指定一个正则表达式模式。 例如,我们可以为每辆山地自行车添加一个名为regex_pat的字符串属性, 其值为"(?i)al"以匹配材料,如前面的例子所示。我们 然后可以将regex_pat与自行车的材料进行匹配:

更新示例

当您想要更新JSON文档的特定部分时,也可以使用JSONPath查询。

例如,你可以传递一个JSONPath到JSON.SET命令来更新特定字段。这个例子改变了耳机列表中第一个商品的价格:

您可以使用过滤表达式来仅更新符合特定条件的JSON元素。以下示例将任何价格已经低于2000的自行车的价格设置为1500:

JSONPath 查询也适用于其他接受路径作为参数的 JSON 命令。例如,您可以使用 JSON.ARRAPPEND 为一副耳机添加新的颜色选项:

旧版路径语法

RedisJSON v1 有以下路径实现。JSON v2 除了支持 JSONPath 外,仍然支持这种旧路径。

路径总是从Redis JSON值的根开始。根由一个句点字符(.)表示。对于引用根的子元素的路径,可以选择在路径前加上根。

Redis JSON 支持使用点符号和括号符号来访问对象键。以下路径指向的是根目录下 inventory 的子项 headphones

  • .inventory.headphones
  • inventory["headphones"]
  • ['inventory']["headphones"]

要访问数组元素,请将其索引括在一对方括号内。索引从0开始,0表示数组的第一个元素,1表示下一个元素,依此类推。您可以使用负偏移量从数组末尾开始访问元素。例如,-1表示数组中的最后一个元素,-2表示倒数第二个元素,依此类推。

JSON 键名和路径兼容性

根据定义,JSON键可以是任何有效的JSON字符串。而路径传统上基于JavaScript(和Java)的变量命名约定。

尽管JSON可以存储包含任意键名的对象,但如果这些键名符合以下命名语法规则,您只能使用传统路径来访问这些键:

  1. 名称必须以字母、美元符号($)或下划线(_)字符开头
  2. 名称可以包含字母、数字、美元符号和下划线
  3. 名称区分大小写

路径评估的时间复杂度

在路径中搜索(导航到)元素的时间复杂度是从以下计算的:

  1. 子级别 - 路径上的每个级别都会增加一次额外的搜索
  2. 键搜索 - O(N),其中 N 是父对象中的键的数量
  3. 数组搜索 - O(1)

这意味着搜索路径的总体时间复杂度为O(N*M),其中N是深度,M是父对象键的数量。

虽然这对于N较小的对象是可以接受的,但对于较大的对象,访问可以进行优化。

RATE THIS PAGE
Back to top ↑