RedisJSON入门

变更记录

时间 描述
2022年5月27日15:04:37 2.介绍中新增特点;
3.安装中增加推荐标记
RedisJSON API命令部分新增: JSON.CLEAR,JSON.FORGET,JSON.RESP,JSON.TOGGLE

1,资料

github: https://github.com/RedisJSON/RedisJSON
website: https://oss.redis.com/redisjson/

2,介绍

  • RedisJSON是什么

    RedisJSON是一个Redis模块,它实现了JSON数据交换标准ECMA-404,作为原生数据类型。它允许从Redis中存储、更新和获取JSON值.
    
  • 特点

    完全支持JSON标准
    使用类似JSONPath的语法,用于在文档中选择元素
    文档以二进制数据的形式存储在树结构中,允许快速访问子元素
    所有JSON值类型都是原子操作
    

使用RediSearch时,支持二级索引


#### 3,安装

##### 3.1,加载模块安装

```sh
方式1:
redis-server --loadmodule /usr/lib/redis/module/rejson.so

方式2(推荐):
在redis.conf中,添加一下内容:
loadmodule /usr/lib/redis/module/rejson.so
3.2,docker安装
  • 运行

    docker run -d -p 6379:6379 --name redis-redisjson -v /redisjson/data:/data redislabs/rejson:latest
    
  • 进入容器

    docker exec -it redis-redisjson bash
    
    问题:
    the input device is not a TTY.  If you are using mintty, try prefixing the command with 'winpty'
    winpty docker exec -it redis-redisjson bash
    
  • 连接

    redis-cli.exe -h 127.0.0.1 -p 6379
    
image-20211222143720651.png
  • 命令行操作

    RedisJSON API命令

    命令和子命令的名称是大写的,例如JSON.SET 和INDENT
    强制参数用尖括号括起来,例如<path>
    可选参数用方括号括起来,例如[index]
    其他可选参数由三个句点字符表示,即...
    管道字符|表示异或
    
    ##标量命令
    #设置json值
    JSON.SET <key> <path> <json> [NX | XX]
    说明:
    NX: 如果不存在就添加
    XX: 如果存在就更新
    
    #查询key的值
    JSON.GET <key> [INDENT indentation-string] [NEWLINE line-break-string] [SPACE space-string] [path ...]
    说明:
    可以接受多个path,默认是root
    INDENT: 设置嵌套级别
    NEWLINE: 每行末尾打印的字符串
    SPACE: 设置key和value之间的字符串
    JSON.GET myjsonkey INDENT "\t" NEWLINE "\n" SPACE " " .
    
    JSON.SET doc $ '{"a":2, "b": 3, "nested": {"a": 4, "b": null}}'
    JSON.GET doc $..b
    JSON.GET doc ..a $..b
    
    
    #查询指定路径下的多个key,不存在的key或path返回null
    JSON.MGET <key> [key ...] <path>
    
    JSON.SET doc1 $ '{"a":1, "b": 2, "nested": {"a": 3}, "c": null}'
    JSON.SET doc2 $ '{"a":4, "b": 5, "nested": {"a": 6}, "c": null}'
    
    JSON.MGET doc1 doc2 $..a
    
    #删除值
    JSON.DEL <key> [path]
    说明: 
    不存在的key或path会被忽略
    返回integer
    
    #增加数字的值
    JSON.NUMINCRBY <key> <path> <number>
    
    #数字乘法,过时了
    JSON.NUMMULTBY <key> <path> <number>
    
    #追加字符串
    JSON.STRAPPEND <key> [path] <json-string>
    
    #字符串的长度
    JSON.STRLEN <key> [path]
    
    ##数组命令
    #追加数组元素
    JSON.ARRAPPEND <key> <path> <json> [json ...]
    
    #搜索指定元素在数组中第一次出现的位置,如果存在返回索引,不存在返回-1
    JSON.ARRINDEX <key> <path> <json-scalar> [start [stop]]
    说明:
    [start [stop]] 从start开始(包含)到stop(不包含)的范围
    
    #在数组指定位置插入元素
    JSON.ARRINSERT <key> <path> <index> <json> [json ...]
    说明:
    index: 0是数组第一个元素,负数表示从末端开始计算
    
    #数组的长度
    JSON.ARRLEN <key> [path]
    说明:
    如果key或path不存在,返回null
    
    #删除返回数组中指定位置的元素
    JSON.ARRPOP <key> [path [index]]
    说明:
    index: 默认是-1,最后一个元素
    
    
    #去掉元素,使其仅包含指定的包含范围的元素
    JSON.ARRTRIM <key> <path> <start> <stop>
    
    ##对象命令
    #返回对象中的key
    JSON.OBJKEYS <key> [path]
    
    #返回对象key的数量
    JSON.OBJLEN <key> [path]
    
    ##模块命令
    #返回json value的数据类型
    JSON.TYPE <key> [path]
    
    #返回key的字节数
    JSON.DEBUG MEMORY <key> [path]
    
    
    

清空容器的值或将数字重置为0(要使用新版本,旧版本,标量值不变)

已经清空的会忽略,返回清空的值的数

JSON.CLEAR key [path]
JSON.SET doc $ '{"obj":{"a":1, "b":2}, "arr":[1,2,3], "str": "foo", "bool": true, "int": 42, "float": 3.14}'

清空,返回4,因为str,bool不会清空

JSON.CLEAR doc $.*

清空所有的,返回1

JSON.CLEAR doc

查询

JSON.GET doc $

删除指定的key的值,返回删除的数量

JSON.FORGET 等同于 json.del

json.set doc "{\"obj\":{},\"arr\":[1,2,3],\"str\":\"foo\",\"bool\":true,\"int\":42,\"float\":3.14}" json.forget doc.str

不支持,没办法使用

以redis序列化协议形式返回json https://redis.io/docs/reference/protocol-spec/#resp-bulk-strings

JSON.RESP key [path]
序列化是转化规则:
JSON Null映射到Bulk string reply
JSON false和true值映射到Simple string reply
JSON Numbers根据类型映射到[]
JSON字符串映射到Bulk string reply
JSON数组表示为[][后面跟着数组的元素
JSON对象表示为[]。

存储一个bool值,通过toggle来切换

redis> JSON.SET doc '{"bool": true}' OK redis> JSON.TOGGLE doc.bool

  1. (integer) 0
    redis> JSON.GET doc "[{\"bool\":false}]" redis> JSON.TOGGLE doc.bool
  2. (integer) 1
    redis> JSON.GET doc $
    "[{"bool":true}]"

字符串

```sh
#添加
127.0.0.1:6379> JSON.SET foo . '"bar"'
OK

#查询
127.0.0.1:6379> JSON.GET foo
"\"bar\""

#类型
127.0.0.1:6379> JSON.TYPE foo
"string"

#字符串长度
127.0.0.1:6379> JSON.STRLEN foo
(integer) 3

#字符串追加
127.0.0.1:6379> json.strappend foo . '"lish"'
(integer) 7

127.0.0.1:6379> json.get foo
"\"barlish\""

数字

#添加num
127.0.0.1:6379> json.set num . 0
OK

#num加1
127.0.0.1:6379> json.numincrby num . 1
"1"

#num加2.5
127.0.0.1:6379> json.numincrby num . 2.5
"3.5"

#num减0.5
127.0.0.1:6379> json.numincrby num . -0.5
"3"

#num乘10
127.0.0.1:6379> json.nummultby num . 10
"30"

127.0.0.1:6379> json.get num
"30.0"

json数据

#添加json字符串
127.0.0.1:6379> JSON.SET user . '{"name":"lcj","age":23}'
OK

#查询
127.0.0.1:6379> JSON.GET user
"{\"name\":\"lcj\",\"age\":23}"

#数据类型
127.0.0.1:6379> JSON.TYPE user
"object"

#数据元素个数
127.0.0.1:6379> json.objlen user
(integer) 2

#所有的key
127.0.0.1:6379> json.objkeys user
1) "name"
2) "age"

数组

#添加空数组
127.0.0.1:6379> json.set arr . []
OK

#追加数据
127.0.0.1:6379> json.arrappend arr . true
(integer) 1
127.0.0.1:6379> json.arrappend arr . '{"answer":42}'
(integer) 2
127.0.0.1:6379> json.arrappend arr . null
(integer) 3

#查询
127.0.0.1:6379> json.get arr
"[true,{\"answer\":42},null]"

#查询数组某个元素
127.0.0.1:6379> json.get arr [1].answer
"42"

#删除最后一个元素
127.0.0.1:6379> json.del arr [-1]
(integer) 1


#指定位置插入数据
127.0.0.1:6379> json.arrinsert arr . 0 -2 -1
(integer) 4

127.0.0.1:6379> json.get arr
"[-2,-1,true,{\"answer\":42}]"

#删除元素,只保留指定范围的元素
127.0.0.1:6379> json.arrtrim arr . 2 3
(integer) 1


#获取数据并删除
127.0.0.1:6379> json.arrpop arr
"true"
127.0.0.1:6379> json.arrpop arr
(nil)
  • 支持的客户端库

    在这里插入图片描述
  • java操作

    maven依赖

    <dependency>
      <groupId>com.redislabs</groupId>
      <artifactId>jrejson</artifactId>
      <version>1.4.0</version>
    </dependency>
    

    github地址

    https://github.com/RedisJSON/JRedisJSON
    

    java代码

    import cn.hutool.core.lang.Console;
    import com.redislabs.modules.rejson.JReJSON;
    import com.redislabs.modules.rejson.Path;
    import org.junit.jupiter.api.Test;
    
    /**
     * <p>
     *      RedisJson测试类
     * </p>
     *
     * @author: liuchangjun
     * @since: 2021/12/22 15:50
     */
    public class RedisJsonTest {
        @Test
        public void test(){
            // 获取连接
            JReJSON client = new JReJSON("127.0.0.1", 6379);
    
            // 添加字符串(路径为根路径)并返回
            client.set("name","lcj", Path.ROOT_PATH);
            String name = client.get("name");
            Console.log("字符串name:{}",name);
    
            name = client.get("name", String.class, Path.of("."));
            Console.log("字符串name:{}",name);
    
            name = client.get("name", String.class, Path.ROOT_PATH);
            Console.log("字符串name:{}",name);
        }
    }
    
3.3,内存使用(实验的和文档不一致)
RedisJSON的数据的值最少占用24字节(64位机器上)
使用json.debug memory key计算大小

字符串最少占用24字节
127.0.0.1:6379> json.set str . '""'
OK
127.0.0.1:6379> json.debug memory str
(integer) 24

数组最少占用24个字节
127.0.0.1:6379> json.set arr . []
OK
127.0.0.1:6379> json.debug memory arr
(integer) 24

json对象最少占用72个字节
127.0.0.1:6379> json.set obj . {}
OK
127.0.0.1:6379> json.debug memory obj
(integer) 72
3.4,路径语法
RedisJSON目前支持两种查询语法:JSONPath语法和RedisJSON第一个版本的路径语法。

RedisJSON根据路径查询的第一个字符决定使用哪种语法。如果查询以字符$开头,则使用JSONPath语法。否则,它默认为路径语法。

JSONPath:
RedisJSON 2.0引入了JSONPath支持。
JSONPath查询可以解析JSON文档中的多个位置。在这种情况下,JSON命令将操作每个可能的位置。这是对遗留查询的重大改进,早期查询只在第一条路径上运行。
注意,在使用JSONPath时,命令响应的结构通常不同。
新语法支持括号表示法,允许在键名中使用特殊字符,如冒号“:”或空格。

Legacy Path syntax (RedisJSON v1):
RedisJSON的第一个版本有以下实现。RedisJSON v2仍然支持它。
路径总是从JSON值的根开始。根由字符(.)表示。对于引用根的子级的路径,可以选择在路径前面加上根前缀。
要访问数组元素,请将其索引括在一对方括号内。索引是基于0的,0是数组的第一个元素。可以使用负偏移来访问从数组末端开始的元素。-1是数组中的最后一个元素

json key的规则:
必须以字符,$,_开头
可以包含字符,数字,$,_
大小写敏感

JSON value规则:
JSON值是指任何有效值。既可以是JSON数组,也可以是JSON对象。JSON标量是一个JSON数字,一个JSON字符串,或一个常量(JSON False, JSON True,或JSON Null)
3.5,搜索和索引
  • 1,索引json文档

    除了存储JSON文档,还可以使用RediSearch模块进行索引,使用全文搜索功能。要使用此功能,必须安装两个模块:RedisJSON和RediSearch。
    
  • 2,索引文档前置要求

    • Redis 6.x or later
    • RedisJSON 2.0 or later
    • RediSearch 2.2 or later
  • 3,创建索引

    语法

    FT.CREATE {index_name} ON JSON SCHEMA {json_path} AS {attribute} {type}
    

    例子

    FT.CREATE userIdx ON JSON SCHEMA $.user.name AS name TEXT $.user.tag AS country TAG
    
  • 4,添加文档

    一旦创建索引,任何预先存在的JSON文档或任何新的JSON文档(添加或修改)都会自动索引。索引是同步的
    
    JSON.SET myDoc $ '{"user":{"name":"John Smith","tag":"foo,bar","hp":1000, "dmg":150}}'
    
  • 5,搜索

    #搜索名字含有John的用户
    127.0.0.1:6379> FT.SEARCH userIdx '@name:(John)'
    1) (integer) 1
    2) "myDoc"
    3) 1) "$"
       2) "{\"user\":{\"name\":\"John Smith\",\"tag\":\"foo,bar\",\"hp\":1000,\"dmg\":150}}"
    
  • 6,字段投影

    默认FT.SEARCH返回整个文档
    
    #返回指定的字段
    FT.SEARCH userIdx '@name:(John)' RETURN 1 name
    
    #使用json路径表达式
    127.0.0.1:6379> FT.SEARCH userIdx '@name:(John)' RETURN 1 $.user.hp
    1) (integer) 1
    2) "myDoc"
    3) 1) "$.user.hp"
       2) "1000"
    
    #返回属性别名
    127.0.0.1:6379> FT.SEARCH userIdx '@name:(John)' RETURN 3 $.user.hp AS hitpoints
    1) (integer) 1
    2) "myDoc"
    3) 1) "hitpoints"
       2) "1000"
    
    
    #高亮
    只要使用文本类型对任何属性进行索引,就可以高亮显示该属性。
    127.0.0.1:6379> FT.SEARCH userIdx '@name:(John)' RETURN 1 name HIGHLIGHT FIELDS 1 name TAGS '<b>' '</b>'
    1) (integer) 1
    2) "myDoc"
    3) 1) "name"
       2) "<b>John</b> Smith"
    
    
  • 7,聚合

    聚合是一个强大的功能。使用它生成统计信息或构建方面查询。LOAD参数接受JSON路径表达式。管道中可以使用任何值(即使没有索引)。
    
    FT.AGGREGATE userIdx * LOAD 6 $.user.hp AS hp $.user.dmg AS dmg APPLY '@hp-@dmg' AS points
    1) (integer) 1
    2) 1) "hp"
       2) "1000"
       3) "dmg"
       4) "150"
       5) "points"
       6) "850"
    
  • 8,索引限制

    1,无法为JSON对象或JSON数组进行索引。

    要索引,JSONPath表达式必须返回单个标量值(字符串或数字)。如果JSONPath表达式返回一个对象或数组,它将被忽略。
    
    #创建索引
    FT.CREATE orgIdx ON JSON SCHEMA $.address[0] AS a1 TEXT $.address[1] AS a2 TEXT
    #添加文档
    JSON.SET org:1 $ '{"name": "Headquarters","address": ["Suite 250","Mountain View"],"cp": "CA 94040"}'
    #搜索
    FT.SEARCH orgIdx "suite 250"
    FT.SEARCH orgIdx "Mountain"
    

    2,将json字符串和数字索引为 TEXT 和NUMERIC

    只能将JSON字符串索引为文本、标记或地理位置
    只能将JSON数字索引为数字
    JSON布尔值只能作为TAG索引
    忽略NULL
    

    3,TAG上不支持排序

    127.0.0.1:6379> FT.CREATE orgIdx2 ON JSON SCHEMA $.cp[0] AS cp TAG SORTABLE
    (error) On JSON, cannot set tag field to sortable - cp
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容