|
| 1 | +[JSONPath](https://goessner.net/articles/JsonPath/) expressions help you access specific elements within a JSON document, which is similar to how XPATH works for XML documents. |
| 2 | +JSONPath support was added to Redis Stack in version 2.0. |
| 3 | +Before that, [a legacy form of pathing](https://redis.io/docs/data-types/json/path/#legacy-path-syntax) was supported. |
| 4 | +Only JSONPath will be discussed in this tutorial. |
| 5 | + |
| 6 | +You've already seen several examples of JSONPath in previous parts of this tutorial. The next sections will describe JSONPath in more complete detail. |
| 7 | +Some simple JSON documents will be used to demonstrate JSONPath's features. |
| 8 | + |
| 9 | +```redis:[run_confirmation=true] Load documents |
| 10 | +JSON.SET lit1 $ 5 |
| 11 | +JSON.SET lit2 $ '"abc"' |
| 12 | +JSON.SET lit3 $ true |
| 13 | +JSON.SET lit4 $ null |
| 14 | +JSON.SET obj1 $ '{"a":1, "b":2}' |
| 15 | +JSON.SET obj2 $ '{"a":[1,2,3,"a","b","c",false,true,["a",1],{"a":1},{"b":null}], "b":5}' |
| 16 | +JSON.SET arr1 $ [1,2,3] |
| 17 | +JSON.SET arrmap $ '[{"a":1}, {"b":2}]' |
| 18 | +``` |
| 19 | + |
| 20 | +**Note**: |
| 21 | +>A JSONPath query can resolve to multiple absolute path matches. When more than one matching path is identified, the JSON commands apply the operation to every possible path. |
| 22 | +
|
| 23 | +## JSONPath syntax |
| 24 | + |
| 25 | +| Syntax element | Description | |
| 26 | +|----------------|-------------| |
| 27 | +| `$` | The root (outermost JSON element), starts the path. | |
| 28 | +| `.` | Selects a child element. | |
| 29 | +| `..` | Recursively descends through the JSON document. | |
| 30 | +| `*` | If current node is an array, `*` resolves to all array elements. If current node is an object, `*` resolves to all the object's members | |
| 31 | +| `[]` | Subscript operator, accesses an array element. | |
| 32 | +| `[,]` | Union, selects multiple elements. | |
| 33 | +| `[start:end:step]` | Array slice where `start`, `end`, and `step` are indexes. | |
| 34 | +| `[?(...)]` | Filters a JSON object or array. Supports comparison operators (`==`, `!=`, `<`, `<=`, `>`, `>=`, `=~`), logical operators (`&&`, `\|\|`), and parentheses for grouping (`(`, `)`). | |
| 35 | +| `@` | The current element, used in filter or script expressions. | |
| 36 | + |
| 37 | +## Basic usage |
| 38 | + |
| 39 | +`$` represents the root of a document. When `$` is combined with `.` and/or `[]`, a child element is selected. Here are a few examples. |
| 40 | + |
| 41 | +```redis $ by itself |
| 42 | +JSON.GET obj1 $ // returns the entire obj1 document |
| 43 | +``` |
| 44 | + |
| 45 | +```redis Select an element with $. |
| 46 | +JSON.GET obj2 $.a // returns the array pointed to by a |
| 47 | +``` |
| 48 | + |
| 49 | +```redis Select an element with $[...] |
| 50 | +JSON.GET arr1 $[1] // returns the second element of the arr1 array |
| 51 | +``` |
| 52 | + |
| 53 | +```redis Select $.a using $.[] notation |
| 54 | +JSON.GET obj2 '$.["a"]' // note the use of single quotes in this expression; they're needed to be able to use double quotes in the expression |
| 55 | +``` |
| 56 | + |
| 57 | +It is possible to use `$` as part of a field name. |
| 58 | + |
| 59 | +```redis:[run_confirmation=true] Using $ as part of a field name |
| 60 | +JSON.SET d $ '{"$":5, "$$":6}' |
| 61 | +JSON.GET d $.$ // returns "[5]" |
| 62 | +``` |
| 63 | + |
| 64 | +The use of quotes is optional when double quotes are not in use inside of an expression. |
| 65 | +Each of the following JSONPath expressions return the same value, `"[5]"`. |
| 66 | + |
| 67 | +```redis Quote usage |
| 68 | +JSON.GET obj2 $.b |
| 69 | +JSON.GET obj2 $.'b' |
| 70 | +JSON.GET obj2 $'.b' |
| 71 | +``` |
| 72 | + |
| 73 | +**Note**: |
| 74 | +>If the current node is not an object or has no member named after the operand, an empty array is returned. |
| 75 | +
|
| 76 | +```redis Invalid path |
| 77 | +JSON.GET obj1 $.c // "[]" is returned |
| 78 | +``` |
| 79 | + |
| 80 | +```redis Combining . and [] |
| 81 | +JSON.GET arrmap $[0].a |
| 82 | +``` |
| 83 | + |
| 84 | +## Bracket (union) expressions |
| 85 | + |
| 86 | +The following syntaxes are supported: |
| 87 | + |
| 88 | +- `'$["value1", "value2", ...]'` |
| 89 | +- `$[idx1, idx2, idx3, ...]` |
| 90 | + |
| 91 | +Each represents a union operation, allowing you to select multiple elements. |
| 92 | + |
| 93 | +For objects, return values are as follows: |
| 94 | + |
| 95 | +- If the current node is an object, an array containing the values of the object’s fields, based on their names, is returned. |
| 96 | +- If the current node is an object and has no members named in the bracket expression, it is skipped. |
| 97 | +This could result in an empty array being returned. |
| 98 | +- If the current node is not an object, an empty array is returned. |
| 99 | + |
| 100 | +Here are some examples: |
| 101 | + |
| 102 | +```redis Bracket union examples with objects |
| 103 | +JSON.GET obj1 '$["a"]' |
| 104 | +JSON.GET obj1 '$["b","b"]' |
| 105 | +JSON.GET obj1 '$["a","c","b","d"]' |
| 106 | +JSON.GET obj1 '$["c","d"]' |
| 107 | +JSON.GET arr1 '$["a","b"]' |
| 108 | +``` |
| 109 | + |
| 110 | +For arrays: |
| 111 | + |
| 112 | +- idx must be an integer |
| 113 | +- if idx < 0, it is replaced with min(0, idx + array-length) |
| 114 | +- if idx ≥ array-length (after normalization) - it is skipped |
| 115 | + |
| 116 | +Return values are as follows: |
| 117 | + |
| 118 | +- If the current node is an array, an array containing elements based on one or more 0-based indexes is returned. |
| 119 | +- If the current node is not an array, it is skipped, possibly resulting in an empty array being returned. |
| 120 | + |
| 121 | +idx must be an integer |
| 122 | +if idx < 0, it is replaced with min(0, idx + array-length) |
| 123 | +if idx ≥ array-length (after normalization) - it is skipped |
| 124 | + |
| 125 | +```redis Bracket union examples with arrays |
| 126 | +JSON.GET obj2 $.a[0] |
| 127 | +JSON.GET obj2 $.a[-1] |
| 128 | +JSON.GET obj2 $.a[100] |
| 129 | +JSON.GET obj2 $.a[-100] |
| 130 | +JSON.GET obj2 $.a[8][1] |
| 131 | +JSON.GET obj2 $.a[0,0,1,1] |
| 132 | +JSON.GET obj2 $.b[0] |
| 133 | +JSON.GET obj2 $.*[0] |
| 134 | +``` |
| 135 | + |
| 136 | +Redis Stack also supports slice syntax for arrays: `[start:`end`:`step`]`, where `start`, `end`, and `step` are indexes. |
| 137 | +If the current node is an array, an array containing elements extracted from an array are returned, based on a `start` index, an `end` index, and a `step` index. |
| 138 | +Array indexes are zero-based; the first element is index 0. Start Index is inclusive; End index is not inclusive. |
| 139 | +The following rules apply: |
| 140 | + |
| 141 | +| Predicate | Rule | |
| 142 | +| --------- | ---- | |
| 143 | +| If `start` is specified | it must be an integer | |
| 144 | +| if `start` is omitted | it is replaced with 0 | |
| 145 | +| if `start` < 0 | it is replaced with min(0, `start` + array-length) | |
| 146 | +| if `start` > array-length | an empty array is returned | |
| 147 | +| if `end` is specified | it must be an integer | |
| 148 | +| If `end` is omitted | it is replaced with array-length | |
| 149 | +| If `end` ≥ array-length | it is replaced with array-length | |
| 150 | +| if `end` < 0 | it is replaced with min(0, `end` + array-length) | |
| 151 | +| If `end` ≤ `start` (after normalization) | an empty array is returned | |
| 152 | +| If `step` is specified | it must be a positive integer | |
| 153 | +| If `step` is omitted | it is replaced with 1 | |
| 154 | +| If the current node in not an array | an empty array is returned | |
| 155 | + |
| 156 | +```redis Array slice examples |
| 157 | +JSON.GET arr1 $[:] |
| 158 | +JSON.GET arr1 $[::] |
| 159 | +JSON.GET arr1 $[::2] |
| 160 | +JSON.GET arr1 $[0:1] |
| 161 | +JSON.GET arr1 $[0:2] |
| 162 | +JSON.GET lit3 $.*[:] |
| 163 | +``` |
| 164 | + |
| 165 | +## Wildcard expressions |
| 166 | + |
| 167 | +The `*` character is a wildcard that expands depending on the type of the current node: |
| 168 | + |
| 169 | +- If the current node is an array, an array containing the values of all the array’s elements is returned. |
| 170 | + |
| 171 | +```redis Using * when the current node is an array |
| 172 | +JSON.GET arr1 $.* // each of the following commands return identical results |
| 173 | +JSON.GET arr1 $[*] |
| 174 | +JSON.GET arr1 $.[*] |
| 175 | +``` |
| 176 | + |
| 177 | +- If the current node is an object, an array containing the values of all the object’s members is returned. |
| 178 | + |
| 179 | +```redis Using * when the current node is an object |
| 180 | +JSON.GET obj1 $.* // each of the following commands return identical results |
| 181 | +JSON.GET obj1 $[*] |
| 182 | +JSON.GET obj1 $.[*] |
| 183 | +``` |
| 184 | + |
| 185 | +- If current node is a literal, an empty array is returned. |
| 186 | + |
| 187 | +```redis Using * when the current node is a literal |
| 188 | +JSON.GET lit1 $.* |
| 189 | +``` |
0 commit comments