路径

访问 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 命令会将操作应用于每个可能的位置。这是对旧版路径查询的重大改进,旧版路径查询只对第一个路径进行操作。

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

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

如果想在 CLI 查询中包含双引号,请将 JSONPath 括在单引号中。例如

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

JSONPath 语法

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

语法元素 描述
$ 根(最外层 JSON 元素),路径的起点。
. 或 [] 选择子元素。
.. 递归下降遍历 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 支持点表示法和方括号表示法来访问对象键。以下路径引用 headphones,它是根下 inventory 的子元素

  • .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 较小的对象来说这可以接受,但对于较大的对象可以优化访问。

评价此页面
返回顶部 ↑