From 08214a5c331460d5b723a3d2d34a717bf0639098 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Mon, 13 May 2024 15:28:41 +0100 Subject: [PATCH 1/4] DOC-3787 add code sample sections to JSON landing page --- content/develop/data-types/json/_index.md | 273 ++++++---------------- 1 file changed, 69 insertions(+), 204 deletions(-) diff --git a/content/develop/data-types/json/_index.md b/content/develop/data-types/json/_index.md index 9408bf25a1..cf6c2d6a5d 100644 --- a/content/develop/data-types/json/_index.md +++ b/content/develop/data-types/json/_index.md @@ -30,107 +30,107 @@ The JSON capability of Redis Stack provides JavaScript Object Notation (JSON) su ## Use Redis JSON -To learn how to use JSON, it's best to start with the Redis CLI. The following examples assume that you're connected to a Redis server with JSON enabled. - -### `redis-cli` examples - -First, start [`redis-cli`]({{< relref "/develop/connect/cli" >}}) in interactive mode. - The first JSON command to try is [`JSON.SET`]({{< baseurl >}}/commands/json.set/), which sets a Redis key with a JSON value. [`JSON.SET`]({{< baseurl >}}/commands/json.set/) accepts all JSON value types. This example creates a JSON string: -```sh -> JSON.SET animal $ '"dog"' -"OK" -> JSON.GET animal $ -"[\"dog\"]" -> JSON.TYPE animal $ +{{< clients-example json_tutorial set_get >}} +> JSON.SET bike $ '"Hyperion"' +OK +> JSON.GET bike $ +"[\"Hyperion\"]" +> JSON.TYPE bike $ 1) "string" -``` +{{< /clients-example >}} Note how the commands include the dollar sign character `$`. This is the [path]({{< relref "/develop/data-types/json/path" >}}) to the value in the JSON document (in this case it just means the root). Here are a few more string operations. [`JSON.STRLEN`]({{< baseurl >}}/commands/json.strlen/) tells you the length of the string, and you can append another string to it with [`JSON.STRAPPEND`]({{< baseurl >}}/commands/json.strappend/). -```sh -> JSON.STRLEN animal $ -1) "3" -> JSON.STRAPPEND animal $ '" (Canis familiaris)"' -1) "22" -> JSON.GET animal $ -"[\"dog (Canis familiaris)\"]" -``` +{{< clients-example json_tutorial str>}} +> JSON.STRLEN bike $ +1) (integer) 8 +> JSON.STRAPPEND bike $ '" (Enduro bikes)"' +1) (integer) 23 +> JSON.GET bike $ +"[\"Hyperion (Enduro bikes)\"]" +{{< /clients-example >}} Numbers can be [incremented]({{< baseurl >}}/commands/json.numincrby/) and [multiplied]({{< baseurl >}}/commands/json.nummultby/): -``` -> JSON.SET num $ 0 +{{< clients-example json_tutorial num >}} +> JSON.SET crashes $ 0 OK -> JSON.NUMINCRBY num $ 1 +> JSON.NUMINCRBY crashes $ 1 "[1]" -> JSON.NUMINCRBY num $ 1.5 +> JSON.NUMINCRBY crashes $ 1.5 "[2.5]" -> JSON.NUMINCRBY num $ -0.75 +> JSON.NUMINCRBY crashes $ -0.75 "[1.75]" -> JSON.NUMMULTBY num $ 24 +> JSON.NUMMULTBY crashes $ 24 "[42]" -``` +{{< /clients-example >}} Here's a more interesting example that includes JSON arrays and objects: -``` -> JSON.SET example $ '[ true, { "answer": 42 }, null ]' +{{< clients-example json_tutorial arr >}} +> JSON.SET newbike $ '["Deimos", {"crashes": 0}, null]' OK -> JSON.GET example $ -"[[true,{\"answer\":42},null]]" -> JSON.GET example $[1].answer -"[42]" -> JSON.DEL example $[-1] +> JSON.GET newbike $ +"[[\"Deimos\",{\"crashes\":0},null]]" +> JSON.GET newbike $[1].crashes +"[0]" +> JSON.DEL newbike $[-1] (integer) 1 -> JSON.GET example $ -"[[true,{\"answer\":42}]]" -``` +> JSON.GET newbike $ +"[[\"Deimos\",{\"crashes\":0}]]" +{{< /clients-example >}} The [`JSON.DEL`]({{< baseurl >}}/commands/json.del/) command deletes any JSON value you specify with the `path` parameter. You can manipulate arrays with a dedicated subset of JSON commands: -``` -> JSON.SET arr $ [] +{{< clients-example json_tutorial arr2 >}} +> JSON.SET riders $ [] OK -> JSON.ARRAPPEND arr $ 0 +> JSON.ARRAPPEND riders $ '"Norem"' 1) (integer) 1 -> JSON.GET arr $ -"[[0]]" -> JSON.ARRINSERT arr $ 0 -2 -1 -1) (integer) 3 -> JSON.GET arr $ -"[[-2,-1,0]]" -> JSON.ARRTRIM arr $ 1 1 +> JSON.GET riders $ +"[[\"Norem\"]]" +> JSON.ARRINSERT riders $ 1 '"Prickett"' '"Royce"' '"Castilla"' +1) (integer) 4 +> JSON.GET riders $ +"[[\"Norem\",\"Prickett\",\"Royce\",\"Castilla\"]]" +> JSON.ARRTRIM riders $ 1 1 1) (integer) 1 -> JSON.GET arr $ -"[[-1]]" -> JSON.ARRPOP arr $ -1) "-1" -> JSON.ARRPOP arr $ +> JSON.GET riders $ +"[[\"Prickett\"]]" +> JSON.ARRPOP riders $ +1) "\"Prickett\"" +> JSON.ARRPOP riders $ 1) (nil) -``` +{{< /clients-example >}} JSON objects also have their own commands: -``` -> JSON.SET obj $ '{"name":"Leonard Cohen","lastSeen":1478476800,"loggedOut": true}' +{{< clients-example json_tutorial obj >}} +> JSON.SET bike:1 $ '{"model": "Deimos", "brand": "Ergonom", "price": 4972}' OK -> JSON.OBJLEN obj $ +> JSON.OBJLEN bike:1 $ 1) (integer) 3 -> JSON.OBJKEYS obj $ -1) 1) "name" - 2) "lastSeen" - 3) "loggedOut" -``` +> JSON.OBJKEYS bike:1 $ +1) 1) "model" + 2) "brand" + 3) "price" +{{< /clients-example >}} + +## Format CLI output -To return a JSON response in a more human-readable format, run `redis-cli` in raw output mode and include formatting keywords such as `INDENT`, `NEWLINE`, and `SPACE` with the [`JSON.GET`]({{< baseurl >}}/commands/json.get/) command: +The CLI has a raw output mode that lets you add formatting to the output from +[`JSON.GET`]({{< baseurl >}}/commands/json.get/) to make +it more readable. To use this, run `redis-cli` with the `--raw` option +and include formatting keywords such as `INDENT`, `NEWLINE`, and `SPACE` +with [`JSON.GET`]({{< baseurl >}}/commands/json.get/): -```sh +{{< clients-example cli only >}} $ redis-cli --raw > JSON.GET obj INDENT "\t" NEWLINE "\n" SPACE " " $ [ @@ -140,147 +140,12 @@ $ redis-cli --raw "loggedOut": true } ] -``` - -### Python example - -This code snippet shows how to use JSON with raw Redis commands from Python with [redis-py](https://github.com/redis/redis-py): - -```Python -import redis - -data = { - 'dog': { - 'scientific-name' : 'Canis familiaris' - } -} - -r = redis.Redis() -r.json().set('doc', '$', data) -doc = r.json().get('doc', '$') -dog = r.json().get('doc', '$.dog') -scientific_name = r.json().get('doc', '$..scientific-name') -``` - -### Run with Docker - -To run RedisJSON with Docker, use the `redis-stack-server` Docker image: - -```sh -$ docker run -d --name redis-stack-server -p 6379:6379 redis/redis-stack-server:latest -``` - -For more information about running Redis Stack in a Docker container, see [Run Redis Stack on Docker]({{< relref "/operate/oss_and_stack/install/install-stack/docker" >}}). - -### Download binaries - -To download and run the RedisJSON module that provides the JSON data structure from a precompiled binary: - -1. Download a precompiled version from the [Redis download center](https://redis.io/downloads). - -2. Load the module it in Redis - - ```sh - $ redis-server --loadmodule /path/to/module/src/rejson.so - ``` - -### Build from source - -To build RedisJSON from the source code: - -1. Clone the [repository](https://github.com/RedisJSON/RedisJSON) (make sure you include the `--recursive` option to properly clone submodules): - - ```sh - $ git clone --recursive https://github.com/RedisJSON/RedisJSON.git - $ cd RedisJSON - ``` - -2. Install dependencies: - - ```sh - $ ./sbin/setup - ``` - -3. Build: - ```sh - $ make build - ``` +{{< /clients-example >}} -### Load the module to Redis +## Limitation -Requirements: - -Generally, it is best to run the latest Redis version. - -If your OS has a [Redis 6.x package or later](http://redis.io/downloads), you can install it using the OS package manager. - -Otherwise, you can invoke - -```sh -$ ./deps/readies/bin/getredis -``` - -To load the RedisJSON module, use one of the following methods: - -* [Makefile recipe](#makefile-recipe) -* [Configuration file](#configuration-file) -* [Command-line option](#command-line-option) -* [MODULE LOAD command]({{< relref "/commands/module-load" >}}) - -#### Makefile recipe - -Run Redis with RedisJSON: - -```sh -$ make run -``` - -#### Configuration file - -Or you can have Redis load the module during startup by adding the following to your `redis.conf` file: - -``` -loadmodule /path/to/module/target/release/librejson.so -``` - -On Mac OS, if this module was built as a dynamic library, run: - -``` -loadmodule /path/to/module/target/release/librejson.dylib -``` - -In the above lines replace `/path/to/module/` with the actual path to the module. - -Alternatively, you can download and run Redis from a precompiled binary: - -1. Download a precompiled version of RedisJSON from the [Redis download center](https://redis.io/downloads). - -#### Command-line option - -Alternatively, you can have Redis load the module using the following command-line argument syntax: - - ```bash - $ redis-server --loadmodule /path/to/module/librejson.so - ``` - -In the above lines replace `/path/to/module/` with the actual path to the module's library. - -#### [`MODULE LOAD`]({{< relref "/commands/module-load" >}}) command - -You can also use the [`MODULE LOAD`]({{< relref "/commands/module-load" >}}) command to load RedisJSON. Note that [`MODULE LOAD`]({{< relref "/commands/module-load" >}}) is a **dangerous command** and may be blocked/deprecated in the future due to security considerations. - -After the module has been loaded successfully, the Redis log should have lines similar to: - -``` -... -9:M 11 Aug 2022 16:24:06.701 * version: 20009 git sha: d8d4b19 branch: HEAD -9:M 11 Aug 2022 16:24:06.701 * Exported RedisJSON_V1 API -9:M 11 Aug 2022 16:24:06.701 * Enabled diskless replication -9:M 11 Aug 2022 16:24:06.701 * Created new data type 'ReJSON-RL' -9:M 11 Aug 2022 16:24:06.701 * Module 'ReJSON' loaded from /opt/redis-stack/lib/rejson.so -... -``` +A JSON value passed to a command can have a depth of up to 128. If you pass to a command a JSON value that contains an object or an array with a nesting level of more than 128, the command returns an error. -### Limitation +## Further information -A JSON value passed to a command can have a depth of up to 128. If you pass to a command a JSON value that contains an object or an array with a nesting level of more than 128, the command returns an error. +Read the other pages in this section to learn more about Redis JSON \ No newline at end of file From 214128c9f47abdedb3ae0bd5ae066c2be9f58853 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Tue, 14 May 2024 12:52:34 +0100 Subject: [PATCH 2/4] DOC-3787 add missing Python samples --- content/develop/data-types/json/path.md | 289 +++++++++++------------- 1 file changed, 138 insertions(+), 151 deletions(-) diff --git a/content/develop/data-types/json/path.md b/content/develop/data-types/json/path.md index eb13b6ba01..7889b2a8d8 100644 --- a/content/develop/data-types/json/path.md +++ b/content/develop/data-types/json/path.md @@ -15,7 +15,7 @@ title: Path weight: 3 --- -Paths help you access specific elements within a JSON document. Since no standard for JSON path syntax exists, Redis JSON implements its own. JSON's syntax is based on common best practices and intentionally resembles [JSONPath](http://goessner.net/articles/JsonPath/). +Paths let you access specific elements within a JSON document. Since no standard for JSON path syntax exists, Redis JSON implements its own. JSON's syntax is based on common best practices and intentionally resembles [JSONPath](http://goessner.net/articles/JsonPath/). JSON supports two query syntaxes: [JSONPath syntax](#jsonpath-syntax) and the [legacy path syntax](#legacy-path-syntax) from the first version of JSON. @@ -34,13 +34,13 @@ Notice that the structure of the command response often differs when using JSONP The new syntax supports bracket notation, which allows the use of special characters like colon ":" or whitespace in key names. -If you want to include double quotes in your query, enclose the JSONPath within single quotes. For example: +If you want to include double quotes in a query from the CLI, enclose the JSONPath within single quotes. For example: -```sh -JSON.GET store '$.inventory["headphones"]' -``` +{{< clients-example cli only >}} +JSON.GET store '$.inventory["mountain_bikes"]' +{{< /clients-example >}} -### JSONPath syntax +## JSONPath syntax The following JSONPath syntax table was adapted from Goessner's [path syntax comparison](https://goessner.net/articles/JsonPath/index.html#e2). @@ -57,204 +57,191 @@ The following JSONPath syntax table was adapted from Goessner's [path syntax com | () | Script expression. | | @ | The current element, used in filter or script expressions. | -### JSONPath examples +## JSONPath examples The following JSONPath examples use this JSON document, which stores details about items in a store's inventory: ```json { - "inventory": { - "headphones": [ - { - "id": 12345, - "name": "Noise-cancelling Bluetooth headphones", - "description": "Wireless Bluetooth headphones with noise-cancelling technology", - "wireless": true, - "connection": "Bluetooth", - "price": 99.98, - "stock": 25, - "free-shipping": false, - "colors": ["black", "silver"] - }, - { - "id": 12346, - "name": "Wireless earbuds", - "description": "Wireless Bluetooth in-ear headphones", - "wireless": true, - "connection": "Bluetooth", - "price": 64.99, - "stock": 17, - "free-shipping": false, - "colors": ["black", "white"] - }, - { - "id": 12347, - "name": "Mic headset", - "description": "Headset with built-in microphone", - "wireless": false, - "connection": "USB", - "price": 35.01, - "stock": 28, - "free-shipping": false - } - ], - "keyboards": [ - { - "id": 22345, - "name": "Wireless keyboard", - "description": "Wireless Bluetooth keyboard", - "wireless": true, - "connection": "Bluetooth", - "price": 44.99, - "stock": 23, - "free-shipping": false, - "colors": ["black", "silver"] - }, - { - "id": 22346, - "name": "USB-C keyboard", - "description": "Wired USB-C keyboard", - "wireless": false, - "connection": "USB-C", - "price": 29.99, - "stock": 30, - "free-shipping": false - } - ] - } + "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}, + }, + ], + } } ``` First, create the JSON document in your database: -```sh -JSON.SET store $ '{"inventory":{"headphones":[{"id":12345,"name":"Noise-cancelling Bluetooth headphones","description":"Wireless Bluetooth headphones with noise-cancelling technology","wireless":true,"connection":"Bluetooth","price":99.98,"stock":25,"free-shipping":false,"colors":["black","silver"]},{"id":12346,"name":"Wireless earbuds","description":"Wireless Bluetooth in-ear headphones","wireless":true,"connection":"Bluetooth","price":64.99,"stock":17,"free-shipping":false,"colors":["black","white"]},{"id":12347,"name":"Mic headset","description":"Headset with built-in microphone","wireless":false,"connection":"USB","price":35.01,"stock":28,"free-shipping":false}],"keyboards":[{"id":22345,"name":"Wireless keyboard","description":"Wireless Bluetooth keyboard","wireless":true,"connection":"Bluetooth","price":44.99,"stock":23,"free-shipping":false,"colors":["black","silver"]},{"id":22346,"name":"USB-C keyboard","description":"Wired USB-C keyboard","wireless":false,"connection":"USB-C","price":29.99,"stock":30,"free-shipping":false}]}}' -``` +{{< clients-example json_tutorial set_bikes >}} +JSON.SET bikes:inventory $ '{ "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\'s 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\'s, this is a bike which doesn\'t break the bank and delivers craved performance. It\'s 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} } ] }}' +{{< /clients-example >}} -#### Access JSON examples +### Access examples The following examples use the [`JSON.GET`]({{< baseurl >}}/commands/json.get/) command to retrieve data from various paths in the JSON document. You can use the wildcard operator `*` to return a list of all items in the inventory: -```sh -127.0.0.1:6379> JSON.GET store $.inventory.* -"[[{\"id\":12345,\"name\":\"Noise-cancelling Bluetooth headphones\",\"description\":\"Wireless Bluetooth headphones with noise-cancelling technology\",\"wireless\":true,\"connection\":\"Bluetooth\",\"price\":99.98,\"stock\":25,\"free-shipping\":false,\"colors\":[\"black\",\"silver\"]},{\"id\":12346,\"name\":\"Wireless earbuds\",\"description\":\"Wireless Bluetooth in-ear headphones\",\"wireless\":true,\"connection\":\"Bluetooth\",\"price\":64.99,\"stock\":17,\"free-shipping\":false,\"colors\":[\"black\",\"white\"]},{\"id\":12347,\"name\":\"Mic headset\",\"description\":\"Headset with built-in microphone\",\"wireless\":false,\"connection\":\"USB\",\"price\":35.01,\"stock\":28,\"free-shipping\":false}],[{\"id\":22345,\"name\":\"Wireless keyboard\",\"description\":\"Wireless Bluetooth keyboard\",\"wireless\":true,\"connection\":\"Bluetooth\",\"price\":44.99,\"stock\":23,\"free-shipping\":false,\"colors\":[\"black\",\"silver\"]},{\"id\":22346,\"name\":\"USB-C keyboard\",\"description\":\"Wired USB-C keyboard\",\"wireless\":false,\"connection\":\"USB-C\",\"price\":29.99,\"stock\":30,\"free-shipping\":false}]]" -``` +{{< clients-example json_tutorial get_bikes >}} +JSON.GET bikes:inventory $.inventory.* +"[[{\"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's 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}}],[{\"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's, this is a bike which doesn't break the bank and delivers craved performance. It's 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}}]]" +{{< /clients-example >}} -For some queries, multiple paths can produce the same results. For example, the following paths return the names of all headphones: +For some queries, multiple paths can produce the same results. For example, the following paths return the names of all mountain bikes: -```sh -127.0.0.1:6379> JSON.GET store $.inventory.headphones[*].name -"[\"Noise-cancelling Bluetooth headphones\",\"Wireless earbuds\",\"Mic headset\"]" -127.0.0.1:6379> JSON.GET store '$.inventory["headphones"][*].name' -"[\"Noise-cancelling Bluetooth headphones\",\"Wireless earbuds\",\"Mic headset\"]" -127.0.0.1:6379> JSON.GET store $..headphones[*].name -"[\"Noise-cancelling Bluetooth headphones\",\"Wireless earbuds\",\"Mic headset\"]" -``` +{{< clients-example json_tutorial get_mtnbikes >}} +> JSON.GET bikes:inventory $.inventory.mountain_bikes[*].model +"[\"Phoebe\",\"Quaoar\",\"Weywot\"]" +> JSON.GET bikes:inventory '$.inventory["mountain_bikes"][*].model' +"[\"Phoebe\",\"Quaoar\",\"Weywot\"]" +> JSON.GET bikes:inventory '$..mountain_bikes[*].model' +"[\"Phoebe\",\"Quaoar\",\"Weywot\"]" +{{< /clients-example >}} The recursive descent operator `..` can retrieve a field from multiple sections of a JSON document. The following example returns the names of all inventory items: -```sh -127.0.0.1:6379> JSON.GET store $..name -"[\"Noise-cancelling Bluetooth headphones\",\"Wireless earbuds\",\"Mic headset\",\"Wireless keyboard\",\"USB-C keyboard\"]" -``` +{{< clients-example json_tutorial get_models >}} +> JSON.GET bikes:inventory $..model +"[\"Phoebe\",\"Quaoar\",\"Weywot\",\"Salacia\",\"Mimas\"]" +{{< /clients-example >}} -You can use an array slice to select a range of elements from an array. This example returns the names of the first two headphones: +You can use an array slice to select a range of elements from an array. This example returns the names of the first 2 mountain bikes: -```sh -127.0.0.1:6379> JSON.GET store $..headphones[0:2].name -"[\"Noise-cancelling Bluetooth headphones\",\"Wireless earbuds\"]" -``` +{{< clients-example json_tutorial get2mtnbikes >}} +> JSON.GET bikes:inventory $..mountain_bikes[0:2].model +"[\"Phoebe\",\"Quaoar\"]" +{{< /clients-example >}} Filter expressions `?()` let you select JSON elements based on certain conditions. You can use comparison operators (`==`, `!=`, `<`, `<=`, `>`, `>=`, and starting with version v2.4.2, also `=~`), logical operators (`&&`, `||`), and parenthesis (`(`, `)`) within these expressions. A filter expression can be applied on an array or on an object, iterating over all the **elements** in the array or all the **values** in the object, retrieving only the ones that match the filter condition. -Paths within the filter condition are using the dot notation with either `@` to denote the current array element or the current object value, or `$` to denote the top-level element. For example, use `@.key_name` to refer to a nested value and `$.top_level_key_name` to refer to a top-level value. +Paths within the filter condition use the dot notation with either `@` to denote the current array element or the current object value, or `$` to denote the top-level element. For example, use `@.key_name` to refer to a nested value and `$.top_level_key_name` to refer to a top-level value. -Starting with version v2.4.2, the comparison operator `=~` can be used for matching a path of a string value on the left side against a regular expression pattern on the right side. For more information, see the [supported regular expression syntax docs](https://docs.rs/regex/latest/regex/#syntax). +From version v2.4.2 onward, you can use the comparison operator `=~` to match a path of a string value on the left side against a regular expression pattern on the right side. For more information, see the [supported regular expression syntax docs](https://docs.rs/regex/latest/regex/#syntax). Non-string values do not match. A match can only occur when the left side is a path of a string value and the right side is either a hard-coded string, or a path of a string value. See [examples](#json-filter-examples) below. -The regex match is partial, meaning `"foo"` regex pattern matches a string such as `"barefoots"`. -To make it exact, use the regex pattern `"^foo$"`. +The regex match is partial, meaning a regex pattern like `"foo"` matches a string such as `"barefoots"`. +To make the match exact, use the regex pattern `"^foo$"`. -Other JSONPath engines may use regex pattern between slashes, e.g., `/foo/`, and their match is exact. -They can perform partial matches using a regex pattern such as `/.*foo.*/`. +Other JSONPath engines may use regex patterns between slashes (for example, `/foo/`), +and their match is exact. They can perform partial matches using a regex pattern such +as `/.*foo.*/`. -#### JSON Filter examples +### Filter examples -In the following example, the filter only returns wireless headphones with a price less than 70: +In the following example, the filter only returns mountain bikes with a price less than 3000 and +a weight less than 10: -```sh -127.0.0.1:6379> JSON.GET store $..headphones[?(@.price<70&&@.wireless==true)] -"[{\"id\":12346,\"name\":\"Wireless earbuds\",\"description\":\"Wireless Bluetooth in-ear headphones\",\"wireless\":true,\"connection\":\"Bluetooth\",\"price\":64.99,\"stock\":17,\"free-shipping\":false,\"colors\":[\"black\",\"white\"]}]" -``` +{{< clients-example json_tutorial filter1 >}} +> JSON.GET bikes:inventory '$..mountain_bikes[?(@.price < 3000 && @.specs.weight < 10)]' +"[{\"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\"]}]" +{{< /clients-example >}} -This example filters the inventory for the names of items that support Bluetooth connections: +This example filters the inventory for the model names of bikes made from alloy: -```sh -127.0.0.1:6379> JSON.GET store '$.inventory.*[?(@.connection=="Bluetooth")].name' -"[\"Noise-cancelling Bluetooth headphones\",\"Wireless earbuds\",\"Wireless keyboard\"]" -``` +{{< clients-example json_tutorial filter2 >}} +> JSON.GET bikes:inventory '$..[?(@.specs.material == "alloy")].model' +"[\"Weywot\",\"Mimas\"]" +{{< /clients-example >}} -This example, starting with version v2.4.2, filters only keyboards with some sort of USB connection using regex match. Notice this match is case-insensitive thanks to the prefix `(?i)` in the regular expression pattern `"(?i)usb"`: +This example, valid from version v2.4.2 onwards, filters only bikes whose material begins with +"al-" using regex match. Note that this match is case-insensitive because of the prefix `(?i)` in +the regular expression pattern `"(?i)al"`: -```sh -127.0.0.1:6379> JSON.GET store '$.inventory.keyboards[?(@.connection =~ "(?i)usb")]' -"[{\"id\":22346,\"name\":\"USB-C keyboard\",\"description\":\"Wired USB-C keyboard\",\"wireless\":false,\"connection\":\"USB-C\",\"price\":29.99,\"stock\":30,\"free-shipping\":false}]" -``` -The regular expression pattern can also be specified using a path of a string value on the right side. +{{< clients-example json_tutorial filter3 >}} +JSON.GET bikes:inventory '$..[?(@.specs.material =~ "(?i)al")].model' +"[\"Quaoar\",\"Weywot\",\"Salacia\",\"Mimas\"]" +{{< /clients-example >}} -For example, let's add each keybaord object with a string value named `regex_pat`: +You can also specify a regex pattern using a property from the JSON object itself. +For example, we can add a string property named `regex_pat` to each mountain bike, +with the value `"(?i)al"` to match the material, as in the previous example. We +can then match `regex_pat` against the bike's material: -```sh -127.0.0.1:6379> JSON.SET store '$.inventory.keyboards[0].regex_pat' '"(?i)bluetooth"' +{{< clients-example json_tutorial filter4 >}} +> JSON.SET bikes:inventory $.inventory.mountain_bikes[0].regex_pat '"(?i)al"' OK -127.0.0.1:6379> JSON.SET store '$.inventory.keyboards[1].regex_pat' '"usb"' +> JSON.SET bikes:inventory $.inventory.mountain_bikes[1].regex_pat '"(?i)al"' OK -``` - -Now we can match against the value of `regex_pat` instead of a hard-coded regular expression pattern, and get the keyboard with the `Bluetooth` string in its `connection` key. Notice the one with `USB-C` does not match since its regular expression pattern is case-sensitive and the regular expression pattern is using lowercase: - -```sh -127.0.0.1:6379> JSON.GET store '$.inventory.keyboards[?(@.connection =~ @.regex_pat)]' -"[{\"id\":22345,\"name\":\"Wireless keyboard\",\"description\":\"Wireless Bluetooth keyboard\",\"wireless\":true,\"connection\":\"Bluetooth\",\"price\":44.99,\"stock\":23,\"free-shipping\":false,\"colors\":[\"black\",\"silver\"],\"regex\":\"(?i)Bluetooth\",\"regex_pat\":\"(?i)bluetooth\"}]" -``` +> JSON.SET bikes:inventory $.inventory.mountain_bikes[2].regex_pat '"(?i)al"' +OK +> JSON.GET bikes:inventory '$.inventory.mountain_bikes[?(@.specs.material =~ @.regex_pat)].model' +"[\"Quaoar\",\"Weywot\"]" +{{< /clients-example >}} -#### Update JSON examples +### Update examples You can also use JSONPath queries when you want to update specific sections of a JSON document. For example, you can pass a JSONPath to the [`JSON.SET`]({{< baseurl >}}/commands/json.set/) command to update a specific field. This example changes the price of the first item in the headphones list: -```sh -127.0.0.1:6379> JSON.GET store $..headphones[0].price -"[99.98]" -127.0.0.1:6379> JSON.SET store $..headphones[0].price 78.99 -"OK" -127.0.0.1:6379> JSON.GET store $..headphones[0].price -"[78.99]" -``` +{{< clients-example json_tutorial update_bikes >}} +> JSON.GET bikes:inventory $..price +"[1920,2072,3264,1475,3941]" +> JSON.NUMINCRBY bikes:inventory $..price -100 +"[1820,1972,3164,1375,3841]" +> JSON.NUMINCRBY bikes:inventory $..price 100 +"[1920,2072,3264,1475,3941]" +{{< /clients-example >}} -You can use filter expressions to update only JSON elements that match certain conditions. The following example changes `free-shipping` to `true` for any items with a price greater than 49: +You can use filter expressions to update only JSON elements that match certain conditions. The following example sets the price of any bike to 1500 if its price is already less than 2000: -```sh -127.0.0.1:6379> JSON.SET store $.inventory.*[?(@.price>49)].free-shipping true -"OK" -127.0.0.1:6379> JSON.GET store $.inventory.*[?(@.free-shipping==true)].name -"[\"Noise-cancelling Bluetooth headphones\",\"Wireless earbuds\"]" -``` +{{< clients-example json_tutorial update_filters1 >}} +> JSON.SET bikes:inventory '$.inventory.*[?(@.price<2000)].price' 1500 +OK +> JSON.GET bikes:inventory $..price +"[1500,2072,3264,1500,3941]" +{{< /clients-example >}} JSONPath queries also work with other JSON commands that accept a path as an argument. For example, you can add a new color option for a set of headphones with [`JSON.ARRAPPEND`]({{< baseurl >}}/commands/json.arrappend/): -```sh -127.0.0.1:6379> JSON.GET store $..headphones[0].colors -"[[\"black\",\"silver\"]]" -127.0.0.1:6379> JSON.ARRAPPEND store $..headphones[0].colors '"pink"' -1) "3" -127.0.0.1:6379> JSON.GET store $..headphones[0].colors -"[[\"black\",\"silver\",\"pink\"]]" -``` +{{< clients-example json_tutorial update_filters2 >}} +> JSON.ARRAPPEND bikes:inventory '$.inventory.*[?(@.price<2000)].colors' '"pink"' +1) (integer) 3 +2) (integer) 3 +127.0.0.1:6379> JSON.GET bikes:inventory $..[*].colors +"[[\"black\",\"silver\",\"pink\"],[\"black\",\"white\"],[\"black\",\"silver\",\"pink\"]]" +{{< /clients-example >}} ## Legacy path syntax From ad165d08343d61fa99a4c61a7f9c37d45f15546c Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Thu, 16 May 2024 15:57:13 +0100 Subject: [PATCH 3/4] DOC-3787 implemented feedback --- content/develop/data-types/json/path.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/develop/data-types/json/path.md b/content/develop/data-types/json/path.md index 7889b2a8d8..957d0d82f3 100644 --- a/content/develop/data-types/json/path.md +++ b/content/develop/data-types/json/path.md @@ -124,7 +124,7 @@ You can use the wildcard operator `*` to return a list of all items in the inven {{< clients-example json_tutorial get_bikes >}} JSON.GET bikes:inventory $.inventory.* -"[[{\"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's 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}}],[{\"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's, this is a bike which doesn't break the bank and delivers craved performance. It's 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}}]]" +"[[{\"id\":\"bike:1\",\"model\":\"Phoebe\",\"description\":\"This is a mid-travel trail slayer... {{< /clients-example >}} For some queries, multiple paths can produce the same results. For example, the following paths return the names of all mountain bikes: @@ -174,7 +174,7 @@ a weight less than 10: {{< clients-example json_tutorial filter1 >}} > JSON.GET bikes:inventory '$..mountain_bikes[?(@.price < 3000 && @.specs.weight < 10)]' -"[{\"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:2\",\"model\":\"Quaoar\",\"description\":\"Redesigned for the 2020 model year... {{< /clients-example >}} This example filters the inventory for the model names of bikes made from alloy: From ede2e746db29b543f26a0646cf18ae22d1589a37 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Fri, 17 May 2024 15:15:12 +0100 Subject: [PATCH 4/4] DOC-3787 restored build/load sections and fixed other minor glitches --- content/develop/data-types/json/_index.md | 126 +++++++++++++++++++++- content/develop/data-types/json/path.md | 4 +- 2 files changed, 126 insertions(+), 4 deletions(-) diff --git a/content/develop/data-types/json/_index.md b/content/develop/data-types/json/_index.md index cf6c2d6a5d..fe07bd0fed 100644 --- a/content/develop/data-types/json/_index.md +++ b/content/develop/data-types/json/_index.md @@ -130,7 +130,7 @@ it more readable. To use this, run `redis-cli` with the `--raw` option and include formatting keywords such as `INDENT`, `NEWLINE`, and `SPACE` with [`JSON.GET`]({{< baseurl >}}/commands/json.get/): -{{< clients-example cli only >}} +```bash $ redis-cli --raw > JSON.GET obj INDENT "\t" NEWLINE "\n" SPACE " " $ [ @@ -140,7 +140,129 @@ $ redis-cli --raw "loggedOut": true } ] -{{< /clients-example >}} +``` + +## Enable Redis JSON + +Redis JSON is implemented as a module that extends the basic Redis server. +Redis Stack and Redis Enterprise include this module by default but you can +also load it dynamically if it isn't already available. The sections below +the different ways you can access Redis JSON. + +### Run with Docker + +To run RedisJSON with Docker, use the `redis-stack-server` Docker image: + +```sh +$ docker run -d --name redis-stack-server -p 6379:6379 redis/redis-stack-server:latest +``` + +For more information about running Redis Stack in a Docker container, see [Run Redis Stack on Docker]({{< relref "/operate/oss_and_stack/install/install-stack/docker" >}}). + +### Download binaries + +To download and run the RedisJSON module that provides the JSON data structure from a precompiled binary: + +1. Download a precompiled version from the [Redis download center](https://redis.io/downloads). + +2. Load the module it in Redis + + ```sh + $ redis-server --loadmodule /path/to/module/src/rejson.so + ``` + +### Build from source + +To build RedisJSON from the source code: + +1. Clone the [repository](https://github.com/RedisJSON/RedisJSON) (make sure you include the `--recursive` option to properly clone submodules): + + ```sh + $ git clone --recursive https://github.com/RedisJSON/RedisJSON.git + $ cd RedisJSON + ``` + +2. Install dependencies: + + ```sh + $ ./sbin/setup + ``` + +3. Build: + ```sh + $ make build + ``` + +### Load the module to Redis + +Requirements: + +Generally, it is best to run the latest Redis version. + +If your OS has a [Redis 6.x package or later](http://redis.io/downloads), you can install it using the OS package manager. + +Otherwise, you can invoke + +```sh +$ ./deps/readies/bin/getredis +``` + +To load the RedisJSON module, use one of the following methods: + +* [Makefile recipe](#makefile-recipe) +* [Configuration file](#configuration-file) +* [Command-line option](#command-line-option) +* [MODULE LOAD command]({{< relref "/commands/module-load" >}}) + +#### Makefile recipe + +Run Redis with RedisJSON: + +```sh +$ make run +``` + +#### Configuration file + +Or you can have Redis load the module during startup by adding the following to your `redis.conf` file: + +``` +loadmodule /path/to/module/target/release/librejson.so +``` + +On Mac OS, if this module was built as a dynamic library, run: + +``` +loadmodule /path/to/module/target/release/librejson.dylib +``` + +In the above lines replace `/path/to/module/` with the actual path to the module. + +#### Command-line option + +You can also have Redis load the module using the following command-line argument syntax: + + ```bash + $ redis-server --loadmodule /path/to/module/librejson.so + ``` + +In the above lines replace `/path/to/module/` with the actual path to the module's library. + +#### [`MODULE LOAD`]({{< relref "/commands/module-load" >}}) command + +You can also use the [`MODULE LOAD`]({{< relref "/commands/module-load" >}}) command to load RedisJSON. Note that [`MODULE LOAD`]({{< relref "/commands/module-load" >}}) is a **dangerous command** and may be blocked/deprecated in the future due to security considerations. + +After the module has been loaded successfully, the Redis log should have lines similar to: + +``` +... +9:M 11 Aug 2022 16:24:06.701 * version: 20009 git sha: d8d4b19 branch: HEAD +9:M 11 Aug 2022 16:24:06.701 * Exported RedisJSON_V1 API +9:M 11 Aug 2022 16:24:06.701 * Enabled diskless replication +9:M 11 Aug 2022 16:24:06.701 * Created new data type 'ReJSON-RL' +9:M 11 Aug 2022 16:24:06.701 * Module 'ReJSON' loaded from /opt/redis-stack/lib/rejson.so +... +``` ## Limitation diff --git a/content/develop/data-types/json/path.md b/content/develop/data-types/json/path.md index 957d0d82f3..ede865f53d 100644 --- a/content/develop/data-types/json/path.md +++ b/content/develop/data-types/json/path.md @@ -36,9 +36,9 @@ The new syntax supports bracket notation, which allows the use of special charac If you want to include double quotes in a query from the CLI, enclose the JSONPath within single quotes. For example: -{{< clients-example cli only >}} +```bash JSON.GET store '$.inventory["mountain_bikes"]' -{{< /clients-example >}} +``` ## JSONPath syntax