

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# JSON 数据类型概述
<a name="json-document-overview"></a>

ElastiCache 支持许多用于处理 JSON 数据类型的 Valkey 和 Redis OSS 命令。以下是 JSON 数据类型的概述和支持的命令的详细列表。

## 术语
<a name="json-terminology"></a>


****  

| 租期 | 描述 | 
| --- | --- | 
|  JSON 文档 | 引用 JSON 键的值。 | 
|  JSON 值 | 指 JSON 文档的子集，包括代表整个文档的根。值可以是容器或容器内的条目。 | 
|  JSON 元素 | 相当于 JSON 值。 | 

## 支持的 JSON 标准
<a name="Supported-JSON-Standard"></a>

JSON 格式符合 [RFC 7159](https://www.ietf.org/rfc/rfc7159.txt) 和 [ECMA-404](https://www.ietf.org/rfc/rfc7159.txt) JSON 数据交换标准。支持 JSON 文本中的 UTF-8 [Unicode](https://www.unicode.org/standard/WhatIsUnicode.html)。

## 根元素
<a name="json-root-element"></a>

根元素可以是任何 JSON 数据类型。请注意，在早期的 RFC 4627 中，只允许将对象或数组作为根值。自 RFC 7159 更新以来，JSON 文档的根目录可以是任何 JSON 数据类型。

## 文档大小限制
<a name="json-document-size-limit"></a>

JSON 文档以针对快速访问和修改而优化的格式在内部存储。此格式通常会导致比同一文档的等效序列化表示使用稍多的内存。

单个 JSON 文档的内存使用限制为 64 MB，这是内存中数据结构的大小，而不是 JSON 字符串的大小。您可以使用 `JSON.DEBUG MEMORY` 命令检查 JSON 文档所使用的内存量。

## JSON ACL
<a name="json-acls"></a>
+ 与现有的每数据类型类别（@string、@hash 等）类似，添加了一个新的类别 @json，以简化对 JSON 命令和数据的访问管理。没有其他现有的 Valkey 或 Redis OSS 命令属于 @json 类别。所有 JSON 命令均强制执行任何键空间或命令限制和权限。
+ 有五个现有的 Valkey 和 Redis OSS ACL 类别已更新为包含新 JSON 命令：@read、@write、@fast、@slow 和 @admin。下表指示 JSON 命令到相应类别的映射。


**ACL**  

| JSON 命令 | @read | @write | @fast | @slow | @admin | 
| --- | --- | --- | --- | --- | --- | 
|  JSON.ARRAPPEND |  | y | y |  |  | 
|  JSON.ARRINDEX | y |  | y |  |  | 
|  JSON.ARRINSERT |  | y | y |  |  | 
|  JSON.ARRLEN | y |  | y |  |  | 
|  JSON.ARRPOP |  | y | y |  |  | 
|  JSON.ARRTRIM |  | y | y |  |  | 
|  JSON.CLEAR |  | y | y |  |  | 
|  JSON.DEBUG | y |  |  | y | y | 
|  JSON.DEL |  | y | y |  |  | 
|  JSON.FORGET |  | y | y |  |  | 
|  JSON.GET | y |  | y |  |  | 
|  JSON.MGET | y |  | y |  |  | 
|  JSON.NUMINCRBY |  | y | y |  |  | 
|  JSON.NUMMULTBY |  | y | y |  |  | 
|  JSON.OBJKEYS | y |  | y |  |  | 
|  JSON.OBJLEN | y |  | y |  |  | 
|  JSON.RESP | y |  | y |  |  | 
|  JSON.SET |  | y |  | y |  | 
|  JSON.STRAPPEND |  | y | y |  |  | 
|  JSON.STRLEN | y |  | y |  |  | 
|  JSON.STRLEN | y |  | y |  |  | 
|  JSON.TOGGLE |  | y | y |  |  | 
|  JSON.TYPE | y |  | y |  |  | 
|  JSON.NUMINCRBY |  | y | y |  |  | 

## 嵌套深度限制
<a name="json-nesting-depth-limit"></a>

当 JSON 对象或数组有一个元素本身就是其他 JSON 对象或数组时，该内部对象或数组被称为“嵌套”在外部对象或数组中。最大嵌套深度上限为 128。任何创建包含嵌套深度大于 128 的文档的尝试都将被拒绝，并出现错误。

## 命令语法
<a name="json-command-syntax"></a>

大多数命令均要求将键名称作为第一个参数。某些命令还带有一个路径参数。如果该路径参数是可选的且未提供，则默认为根目录。

 表示法：
+ 必需的参数括在尖括号内。例如：<key>
+ 可选的参数括在方括号内。例如：[path]
+ 其他可选参数由省略号（“…”）来表示。例如：[json ...]

## 路径语法
<a name="json-path-syntax"></a>

Redis JSON 支持两种路径语法：
+ **增强的语法** – 遵循由 [Goessner](https://goessner.net/articles/JsonPath/) 描述的 JSONPath 语法，如下表所示。我们对表中的描述进行了重新排序和修改使其更加清楚。
+ **受限的语法** – 查询功能有限。

**注意**  
某些命令的结果对使用哪种类型的路径语法很敏感。

 如果查询路径以“\$1”开头，则使用的是增强的语法。否则使用的是受限的语法。

**增强的语法**


****  

| 符号/表达式 | 描述 | 
| --- | --- | 
|  \$1 | 根元素。 | 
|  . 或 [] | 子运算符。 | 
|  .. | 递归下降。 | 
|  \$1 | 通配符。对象或数组中的所有元素。 | 
|  [] | 数组下标运算符。索引从 0 开始。 | 
|  [,] | 联合运算符。 | 
|  [start:end:step] | 数组 Slice 运算符。 | 
|  ?() | 将筛选（脚本）表达式应用于当前的数组或对象。 | 
|  () | 筛选表达式。 | 
|  @ | 用于引用当前正在处理的节点的筛选表达式。 | 
|  == | 等于，用于筛选表达式。 | 
|  \$1= | 不等于，用于筛选表达式。 | 
|  > | 大于，用于筛选表达式。 | 
|  >= | 大于或等于，用于筛选表达式。 | 
|  < | 小于，用于筛选表达式。 | 
|  <= | 小于或等于，用于筛选表达式。 | 
|  && | 逻辑 AND，用于组合多个筛选表达式。 | 
|  \$1\$1 | L逻辑 OR，用于组合多个筛选表达式。 | 

**示例**

以下示例基于 [Goessner](https://goessner.net/articles/JsonPath/) 的示例 XML 数据而构建，我们已通过添加其他字段对数据进行了修改。

```
{ "store": {
    "book": [ 
      { "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95,
        "in-stock": true,
        "sold": true
      },
      { "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99,
        "in-stock": false,
        "sold": true
      },
      { "category": "fiction",
        "author": "Herman Melville",
        "title": "Moby Dick",
        "isbn": "0-553-21311-3",
        "price": 8.99,
        "in-stock": true,
        "sold": false
      },
      { "category": "fiction",
        "author": "J. R. R. Tolkien",
        "title": "The Lord of the Rings",
        "isbn": "0-395-19395-8",
        "price": 22.99,
        "in-stock": false,
        "sold": false
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95,
      "in-stock": true,
      "sold": false
    }
  }
}
```


****  

| 路径 | 描述 | 
| --- | --- | 
|  \$1.store.book[\$1].author | 商店中所有书籍的作者。 | 
|  \$1..author | 所有作者。 | 
|  \$1.store.\$1 | 商店的所有成员。 | 
|  \$1["store"].\$1 | 商店的所有成员。 | 
|  \$1.store..price | 商店中所有商品的价格。 | 
|  \$1..\$1 | JSON 结构的所有递归成员。 | 
|  \$1..book[\$1] | 所有书籍。 | 
|  \$1..book[0] | 第一本书籍。 | 
|  \$1..book[-1] | 最后一本书籍。 | 
|  \$1..book[0:2] | 前两本书籍。 | 
|  \$1..book[0,1] | 前两本书籍。 | 
|  \$1..book[0:4] | 从索引 0 到 3 的书籍（不包括结尾索引）。 | 
|  \$1..book[0:4:2] | 索引为 0、2 的书籍。 | 
|  \$1..book[?(@.isbn)] | 所有带 ISBN 编号的书籍。 | 
|  \$1..book[?(@.price<10)] | 所有价格低于 10 美元的书籍。 | 
|  '\$1..book[?(@.price < 10)]' | 所有价格低于 10 美元的书籍。（如果路径包含空格，则必须用引号将其引起来。） | 
|  '\$1..book[?(@["price"]< 10)]' | 所有价格低于 10 美元的书籍。 | 
|  '\$1..book[?(@.["price"]< 10)]' | 所有价格低于 10 美元的书籍。 | 
|  \$1..book[?(@.price>=10&&@.price<=100)] | 所有价格在 10 美元到 100 美元之间（含 10 美元和 100 美元）的书籍。 | 
|  '\$1..book[?(@.price>=10 && @.price<=100)]' | 所有价格在 10 美元到 100 美元之间（含 10 美元和 100 美元）的书籍。（如果路径包含空格，则必须用引号将其引起来。） | 
|  \$1..book[?(@.sold==true\$1\$1@.in-stock==false)] | 所有书籍已售出或缺货。 | 
|  '\$1..book[?(@.sold == true \$1\$1 @.in-stock == false)]' | 所有书籍已售出或缺货。（如果路径包含空格，则必须用引号将其引起来。） | 
|  '\$1.store.book[?(@.["category"] == "fiction")]' | 所有小说类书籍。 | 
|  '\$1.store.book[?(@.["category"] \$1= "fiction")]' | 所有非小说类书籍。 | 

其他筛选表达式示例：

```
127.0.0.1:6379> JSON.SET k1 . '{"books": [{"price":5,"sold":true,"in-stock":true,"title":"foo"}, {"price":15,"sold":false,"title":"abc"}]}'
OK
127.0.0.1:6379> JSON.GET k1 $.books[?(@.price>1&&@.price<20&&@.in-stock)]
"[{\"price\":5,\"sold\":true,\"in-stock\":true,\"title\":\"foo\"}]"
127.0.0.1:6379> JSON.GET k1 '$.books[?(@.price>1 && @.price<20 && @.in-stock)]'
"[{\"price\":5,\"sold\":true,\"in-stock\":true,\"title\":\"foo\"}]"
127.0.0.1:6379> JSON.GET k1 '$.books[?((@.price>1 && @.price<20) && (@.sold==false))]'
"[{\"price\":15,\"sold\":false,\"title\":\"abc\"}]"
127.0.0.1:6379> JSON.GET k1 '$.books[?(@.title == "abc")]'
[{"price":15,"sold":false,"title":"abc"}]

127.0.0.1:6379> JSON.SET k2 . '[1,2,3,4,5]'
127.0.0.1:6379> JSON.GET k2 $.*.[?(@>2)]
"[3,4,5]"
127.0.0.1:6379> JSON.GET k2 '$.*.[?(@ > 2)]'
"[3,4,5]"

127.0.0.1:6379> JSON.SET k3 . '[true,false,true,false,null,1,2,3,4]'
OK
127.0.0.1:6379> JSON.GET k3 $.*.[?(@==true)]
"[true,true]"
127.0.0.1:6379> JSON.GET k3 '$.*.[?(@ == true)]'
"[true,true]"
127.0.0.1:6379> JSON.GET k3 $.*.[?(@>1)]
"[2,3,4]"
127.0.0.1:6379> JSON.GET k3 '$.*.[?(@ > 1)]'
"[2,3,4]"
```

**受限的语法**


****  

| 符号/表达式 | 描述 | 
| --- | --- | 
|  . 或 [] | 子运算符。 | 
|  [] | 数组下标运算符。索引从 0 开始。 | 

**示例**


****  

| 路径 | 描述 | 
| --- | --- | 
|  .store.book[0].author | 第一本书籍的作者。 | 
|  .store.book[-1].author | 最后一本书籍的作者。 | 
|  .address.city | 城市名称。 | 
|  ["store"]["book"][0]["title"] | 第一本书籍的书名。 | 
|  ["store"]["book"][-1]["title"] | 最后一本书籍的书名。 | 

**注意**  
本文档中引用的所有 [Goessner](https://goessner.net/articles/JsonPath/) 内容均受[知识共享许可证](https://creativecommons.org/licenses/by/2.5/)的约束。

## 常见错误前缀
<a name="json-error-prefixes"></a>

每条错误消息均有一个前缀。以下是常见错误前缀的列表。


****  

| Prefix | 描述 | 
| --- | --- | 
|  ERR | 一般性错误。 | 
|  LIMIT | 超出大小限制时发生的错误。例如，超出了文档大小限制或嵌套深度限制。 | 
|  NONEXISTENT | 键或路径不存在。 | 
|  OUTOFBOUNDARIES | 数组索引超出界限。 | 
|  SYNTAXERR | 语法错误。 | 
|  WRONGTYPE | 错误的值类型。 | 

## JSON 相关指标
<a name="json-info-metrics"></a>

提供了以下 JSON 信息指标：


****  

| Info | 描述 | 
| --- | --- | 
|  json\$1total\$1memory\$1bytes | 分配给 JSON 对象的总内存。 | 
|  json\$1num\$1documents | Valkey 或 Redis OSS 中的文档总数。 | 

要查询核心指标，请运行以下命令：

```
info json_core_metrics
```

## ElastiCache for Valkey 和 ElastiCache for Redis OSS 如何与 JSON 交互
<a name="json-differences"></a>

以下部分介绍了 ElastiCache for Valkey 和 ElastiCache for Redis OSS 如何与 JSON 数据类型交互。

### 运算符优先顺序
<a name="json-operator-precedence"></a>

当评估条件表达式以进行筛选时，&& 优先评估，然后评估 \$1\$1，这一点在大多数语言中很常见。首先运行括号内的运算符。

### 最大路径嵌套限制行为
<a name="json-max-path"></a>

 ElastiCache for Redis OSS 中的最大路径嵌套限制为 128。因此，像 `$.a.b.c.d...` 这样的值只能达到 128 个级别。

### 处理数字值
<a name="json-about-numbers"></a>

JSON 没有针对整数和浮点数的单独数据类型。它们都被称为数字。

数字的表示形式：

当在输入时接收 JSON 数字时，它会转换为两种内部二进制表示之一：64 位有符号整数或 64 位 IEEE 双精度浮点。不保留原始字符串及其所有格式。因此，当数字作为 JSON 响应的一部分输出时，它会从内部二进制表示转换为使用通用格式规则的可打印字符串。这些规则可能会导致生成的字符串与收到的字符串不同。

算术命令 `NUMINCRBY` 和 `NUMMULTBY`：
+ 如果两个数字都是整数并且结果超出 `int64` 的范围，则它会自动变成一个 64 位 IEEE 双精度浮点数。
+ 如果至少有一个数字是浮点，则结果是 64 位 IEEE 双精度浮点数。
+ 如果结果超出 64 位 IEEE 双精度值的范围，则该命令将返回 `OVERFLOW` 错误。

有关可用命令的详细列表，请参阅 [支持的 Valkey 和 Redis OSS 命令JSON 命令](json-list-commands.md)。

### 直接数组筛选
<a name="json-direct-array-filtering"></a>

ElastiCache for Valkey 和 ElastiCache for Redis OSS 可直接筛选数组对象。

对于像 `[0,1,2,3,4,5,6]` 这样的数据和像 `$[?(@<4)]` 这样的路径查询，或者像 `{"my_key":[0,1,2,3,4,5,6]}` 这样的数据和像 `$.my_key[?(@<4)]` 这样的路径查询，在这两种情况下，ElastiCache 都会返回 [1,2,3]。

### 数组索引行为
<a name="json-direct-array-indexing"></a>

ElastiCache for Valkey 和 ElastiCache for Redis OSS 允许数组的正索引和负索引。对于长度为 5 的数组，0 将查询第一个元素，1 将查询第二个元素，依此类推。负数从数组的末尾开始，因此 -1 将查询第五个元素，-2 将查询第四个元素，依此类推。

为确保客户行为可预测，ElastiCache 不会向下或向上舍入数组索引，因此如果您有一个长度为 5 的数组，则调用索引 5 及更高或 -6 及更低将不会产生结果。

### 严格语法评估
<a name="json-strict-syntax-evaluation"></a>

MemoryDB 不允许使用无效语法的 JSON 路径，即使路径的子集包含有效路径也是如此。这是为了维护我们客户的正确行为。