

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# JSON 資料類型概觀
<a name="json-document-overview"></a>

MemoryDB 支援許多使用 JSON 資料類型的 Valkey 和 Redis OSS 命令。以下是 JSON 資料類型的概觀，以及支援命令的詳細清單。

## 術語
<a name="json-terminology"></a>


****  

| 術語 | Description | 
| --- | --- | 
|  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 文件的記憶體使用量限制為 64MB，即記憶體內資料結構的大小，而非 JSON 字串。您可以使用 `JSON.DEBUG MEMORY`命令來檢查 JSON 文件耗用的記憶體量。

## JSON ACL
<a name="json-acls"></a>
+ JSON 資料類型已完全整合至 Valkey 和 Redis OSS [存取控制清單 (ACL)](https://valkey.io/topics/acl/) 功能。與現有的每個資料類型類別 (@string、@hash 等） 類似，會新增新類別 @json，以簡化對 JSON 命令和資料的管理存取。沒有其他現有的 Valkey 或 Redis OSS 命令是 @json 類別的成員。所有 JSON 命令都會強制執行任何索引鍵空間或命令限制和許可。
+ 已更新五個現有的 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>

大多數命令需要 Valkey 或 Redis OSS 金鑰名稱做為第一個引數。部分命令也有路徑引數。如果路徑引數為選用且未提供，則路徑引數預設為根。

 標記法：
+ 必要的引數以角括號括住，例如 <key>
+ 選用引數以方括號括住，例如 【path】
+ 其他選用引數會以 ... 表示，例如 【json ...】

## 路徑語法
<a name="json-path-syntax"></a>

JSON for Valkey 和 Redis OSS 支援兩種路徑語法：
+ **增強型語法** – 遵循 [Goessner](https://goessner.net/articles/JsonPath/) 所述的 JSONPath 語法，如下表所示。為清楚說明，我們重新排序並修改表格中的描述。
+ **受限語法** – 查詢功能有限。

**注意**  
某些命令的結果會區分使用的路徑語法類型。

 如果查詢路徑以 '\$1' 開頭，它會使用增強型語法。否則，將使用受限語法。

**增強型語法**


****  

| 符號/表達式 | Description | 
| --- | --- | 
|  \$1 | 根元素 | 
|  . 或 [] | 子運算子 | 
|  .. | 遞迴下降 | 
|  \$1 | 萬用字元。物件或陣列中的所有元素。 | 
|  [] | array subscript 運算子。索引以 0 為基礎。 | 
|  [,] | 聯集運算子 | 
|  [start:end:step] | 陣列配量運算子 | 
|  ?() | 將篩選條件 (script) 表達式套用至目前的陣列或物件 | 
|  () | 篩選條件表達式 | 
|  @ | 用於參考正在處理的目前節點的篩選條件表達式 | 
|  == | 等於，用於篩選條件表達式。 | 
|  \$1= | 不等於，用於篩選條件表達式。 | 
|  > | 大於，用於篩選條件表達式。 | 
|  >= | 大於或等於，用於篩選條件表達式。 | 
|  < | 小於，用於篩選條件表達式。 | 
|  <= | 小於或等於，用於篩選條件表達式。 | 
|  && | 邏輯 AND，用於結合多個篩選條件表達式。 | 
|  \$1\$1 | 邏輯 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
    }
  }
}
```


****  

| 路徑 | Description | 
| --- | --- | 
|  \$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 USD 的所有書籍 | 
|  '\$1..book[?(@.price < 10)]' | 低於 10 USD 的所有書籍。（如果包含空格，則必須引用路徑） | 
|  '\$1..book[?(@["price"] < 10)]' | 低於 10 USD 的所有書籍 | 
|  '\$1..book[?(@.["price"] < 10)]' | 低於 10 USD 的所有書籍 | 
|  \$1..book[?(@.price>=10&&@.price<=100)] | 價格範圍介於 \$110 到 \$1100 的所有書籍，包括 | 
|  '\$1..book[?(@.price>=10 && @.price<=100)]' | 價格範圍介於 \$110 到 \$1100 的所有書籍，包括在內。（如果包含空格，則必須引用路徑） | 
|  \$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]"
```

**受限語法**


****  

| 符號/表達式 | Description | 
| --- | --- | 
|  . 或 [] | 子運算子 | 
|  [] | array subscript 運算子。索引以 0 為基礎。 | 

**範例**


****  

| 路徑 | Description | 
| --- | --- | 
|  .store.book[0].author | 第一本書籍的作者 | 
|  .store.book[-1].author | 最後一本書的作者 | 
|  .address.city | 城市名稱 | 
|  ["store"]["book"][0]["title"] | 第一本書的標題 | 
|  ["store"]["book"][-1]["title"] | 最後一本書的標題 | 

**注意**  
本文件中引用的所有 [Goessner](https://goessner.net/articles/JsonPath/) 內容均受[創用 CC 授權](https://creativecommons.org/licenses/by/2.5/)規範。

## 常見錯誤字首
<a name="json-error-prefixes"></a>

每個錯誤訊息都有一個字首。以下是常見錯誤字首的清單：


****  

| 字首 | Description | 
| --- | --- | 
|  ERR | 一般錯誤 | 
|  LIMIT | 超過大小限制錯誤。例如，超過文件大小限制或巢狀深度限制 | 
|  NONEXISTENT | 金鑰或路徑不存在 | 
|  OUTOFBOUNDARIES | 陣列索引超出範圍 | 
|  SYNTAXERR | 語法錯誤 | 
|  WRONGTYPE | 錯誤的值類型 | 

## JSON 相關指標
<a name="json-info-metrics"></a>

提供下列 JSON 資訊指標：


****  

| 資訊 | Description | 
| --- | --- | 
|  json\$1total\$1memory\$1bytes | 配置給 JSON 物件的記憶體總數 | 
|  json\$1num\$1documents | Valkey 或 Redis OSS 引擎中的文件總數 | 

若要查詢核心指標，請執行 命令：

```
info json_core_metrics
```

## MemoryDB 如何與 JSON 互動
<a name="json-differences"></a>

以下說明 MemoryDB 如何與 JSON 資料類型互動。

### 運算子優先順序
<a name="json-operator-precedence"></a>

評估用於篩選的條件表達式時，&& 優先，然後評估 \$1\$1，就像大多數語言一樣。括號內的操作會先執行。

### 路徑巢狀上限行為
<a name="json-max-path"></a>

MemoryDB 的路徑巢狀限制上限為 128。`$.a.b.c.d...` 等值只能達到 128 個等級。

### 處理數值
<a name="json-about-numbers"></a>

JSON 對於整數和浮點數沒有單獨的資料類型。均稱為數字。

收到 JSON 號碼時，會以兩種格式之一存放。如果數字符合 64 位元帶正負號的整數，則會轉換為該格式；否則會儲存為字串。兩個 JSON 號碼 （例如 JSON.NUMINCRBY 和 JSON.NUMMULTBY) 的算術操作會嘗試盡可能保持精確度。如果兩個運算元和產生的值符合 64 位元帶正負號的整數，則會執行整數算術。否則，輸入運算元會轉換為 64 位元 IEEE 雙精度浮點數、執行算術操作，並將結果轉換回字串。

算術命令 `NUMINCRBY` 和 `NUMMULTBY`：
+ 如果兩個數字都是整數，且結果超出 int64 的範圍，則會自動成為雙精度浮點數。
+ 如果至少一個數字是浮點數，則結果將是雙精度浮點數。
+ 如果結果超過兩倍的範圍，命令將傳回`OVERFLOW`錯誤。

**注意**  
在輸入時收到 JSON 號碼時，在 Redis OSS 引擎版本 6.2.6.R2 之前，它會轉換為兩個內部二進位表示式之一：64 位元帶正負號的整數或 64 位元 IEEE 雙精度浮點。不會保留原始字串和全部格式化。因此，數字當作 JSON 回應的一部分輸出時，會從內部二進位表示法，轉換為使用一般格式化規則的可列印字串。這些規則可能導致產生的字串與接收的字串不同。  
如果兩個數字都是整數，且結果超出 `int64` 範圍，會自動變成 64 位元 IEEE 雙精確度浮點數。
如果其中至少一個數字是浮點數，結果會是 64 位元 IEEE 雙精確度浮點數。
如果結果超過 64 位元 IEEE 雙精確度範圍，命令會傳回 `OVERFLOW` 錯誤。

如需可用命令的詳細清單，請參閱[支援的命令](json-list-commands.md)。

### 嚴格語法評估
<a name="json-strict-syntax-evaluation"></a>

即使路徑的子集包含有效路徑，MemoryDB 也不允許使用無效語法的 JSON 路徑。這是為了我們的客戶保持正確行為。