golang Redis中JSON数据结构存储与操作插件库go-rejson的使用

Golang Redis中JSON数据结构存储与操作插件库go-rejson的使用

注意事项

目前go-ReJSON仅支持redislabs/rejson版本<=1.0.8。如果您使用更高版本,某些命令可能无法按预期工作。

Go-ReJSON简介

Go-ReJSON是一个用于ReJSON Redis模块的Go客户端。ReJSON是一个Redis模块,实现了ECMA-404 JSON数据交换标准作为原生数据类型,允许在Redis键(文档)中存储、更新和获取JSON值。

ReJSON模块的主要特性

  • 完整支持JSON标准
  • 使用类似JSONPath的语法选择文档中的元素
  • 文档以二进制数据存储在树结构中,可以快速访问子元素
  • 为所有JSON值类型提供类型化原子操作

安装

go get github.com/nitishm/go-rejson/v4

使用示例

完整示例代码

package main

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"log"

	"github.com/nitishm/go-rejson/v4"
	goredis "github.com/go-redis/redis/v8"
	"github.com/gomodule/redigo/redis"
)

// Name - 学生姓名
type Name struct {
	First  string `json:"first,omitempty"`
	Middle string `json:"middle,omitempty"`
	Last   string `json:"last,omitempty"`
}

// Student - 学生对象
type Student struct {
	Name Name `json:"name,omitempty"`
	Rank int  `json:"rank,omitempty"`
}

func Example_JSONSet(rh *rejson.Handler) {
	// 创建学生对象
	student := Student{
		Name: Name{
			"Mark",
			"S",
			"Pronto",
		},
		Rank: 1,
	}
	
	// 将学生对象存储到Redis
	res, err := rh.JSONSet("student", ".", student)
	if err != nil {
		log.Fatalf("Failed to JSONSet")
		return
	}

	if res.(string) == "OK" {
		fmt.Printf("Success: %s\n", res)
	} else {
		fmt.Println("Failed to Set: ")
	}

	// 从Redis获取学生对象
	studentJSON, err := redis.Bytes(rh.JSONGet("student", "."))
	if err != nil {
		log.Fatalf("Failed to JSONGet")
		return
	}

	// 反序列化JSON数据
	readStudent := Student{}
	err = json.Unmarshal(studentJSON, &readStudent)
	if err != nil {
		log.Fatalf("Failed to JSON Unmarshal")
		return
	}

	fmt.Printf("Student read from redis : %#v\n", readStudent)
}

func main() {
	var addr = flag.String("Server", "localhost:6379", "Redis server address")

	rh := rejson.NewReJSONHandler()
	flag.Parse()

	// 使用Redigo客户端
	conn, err := redis.Dial("tcp", *addr)
	if err != nil {
		log.Fatalf("Failed to connect to redis-server @ %s", *addr)
	}
	defer func() {
		_, err = conn.Do("FLUSHALL")
		err = conn.Close()
		if err != nil {
			log.Fatalf("Failed to communicate to redis-server @ %v", err)
		}
	}()
	rh.SetRedigoClient(conn)
	fmt.Println("Executing Example_JSONSET for Redigo Client")
	Example_JSONSet(rh)

	// 使用GoRedis客户端
	cli := goredis.NewClient(&goredis.Options{Addr: *addr})
	defer func() {
		if err := cli.FlushAll(context.Background()).Err(); err != nil {
			log.Fatalf("goredis - failed to flush: %v", err)
		}
		if err := cli.Close(); err != nil {
			log.Fatalf("goredis - failed to communicate to redis-server: %v", err)
		}
	}()
	rh.SetGoRedisClient(cli)
	fmt.Println("\nExecuting Example_JSONSET for GoRedis Client")
	Example_JSONSet(rh)
}

代码说明

  1. 首先定义了两个结构体NameStudent,用于表示学生信息
  2. Example_JSONSet函数演示了如何使用go-rejson:
    • 创建一个学生对象
    • 使用JSONSet方法将对象存储到Redis
    • 使用JSONGet方法从Redis获取数据
    • 将获取的JSON数据反序列化为结构体
  3. main函数展示了如何同时使用Redigo和GoRedis两种Redis客户端

主要方法

  • JSONSet(key string, path string, obj interface{}): 将对象存储为Redis中的JSON
  • JSONGet(key string, path string): 从Redis获取JSON数据

这个示例展示了go-rejson的基本用法,您可以根据需要扩展功能,如使用更复杂的JSONPath查询、更新部分JSON数据等。


更多关于golang Redis中JSON数据结构存储与操作插件库go-rejson的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang Redis中JSON数据结构存储与操作插件库go-rejson的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


go-rejson: Redis中JSON数据结构存储与操作指南

go-rejson是一个用于在Redis中存储和操作JSON数据的Golang库,它基于Redis的ReJSON模块。下面我将详细介绍如何使用go-rejson进行JSON数据的存储和操作。

安装

首先需要安装go-rejson库和Redis服务器(确保Redis已加载ReJSON模块):

go get github.com/nitishm/go-rejson/v4

基本使用

1. 初始化连接

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/go-redis/redis/v8"
	"github.com/nitishm/go-rejson/v4"
)

func main() {
	// 创建Redis客户端
	rdb := redis.NewClient(&redis.Options{
		Addr: "localhost:6379",
	})

	// 创建ReJSON处理器
	rh := rejson.NewReJSONHandler()
	rh.SetGoRedisClient(rdb)

	ctx := context.Background()

	// 测试连接
	if _, err := rdb.Ping(ctx).Result(); err != nil {
		log.Fatalf("Failed to connect to Redis: %v", err)
	}
}

2. 存储JSON数据

type User struct {
	Name    string `json:"name"`
	Age     int    `json:"age"`
	Address struct {
		City    string `json:"city"`
		Country string `json:"country"`
	} `json:"address"`
}

func setJSON(rh *rejson.Handler) {
	ctx := context.Background()
	
	user := User{
		Name: "John Doe",
		Age:  30,
		Address: struct {
			City    string `json:"city"`
			Country string `json:"country"`
		}{
			City:    "New York",
			Country: "USA",
		},
	}

	// 设置JSON对象到Redis
	res, err := rh.JSONSet("user:123", ".", user)
	if err != nil {
		log.Fatalf("Failed to JSONSet: %v", err)
	}
	
	if res.(string) == "OK" {
		fmt.Println("Success: user:123")
	}
}

3. 获取JSON数据

func getJSON(rh *rejson.Handler) {
	ctx := context.Background()
	
	var user User
	// 获取整个JSON对象
	_, err := rh.JSONGet("user:123", ".", &user)
	if err != nil {
		log.Fatalf("Failed to JSONGet: %v", err)
	}
	
	fmt.Printf("User: %+v\n", user)
	
	// 获取特定字段
	var name string
	_, err = rh.JSONGet("user:123", ".name", &name)
	if err != nil {
		log.Fatalf("Failed to JSONGet name: %v", err)
	}
	fmt.Printf("Name: %s\n", name)
}

4. 更新JSON数据

func updateJSON(rh *rejson.Handler) {
	ctx := context.Background()
	
	// 更新单个字段
	res, err := rh.JSONSet("user:123", ".age", 31)
	if err != nil {
		log.Fatalf("Failed to update age: %v", err)
	}
	
	if res.(string) == "OK" {
		fmt.Println("Successfully updated age")
	}
	
	// 更新嵌套字段
	res, err = rh.JSONSet("user:123", ".address.city", "Boston")
	if err != nil {
		log.Fatalf("Failed to update city: %v", err)
	}
	
	if res.(string) == "OK" {
		fmt.Println("Successfully updated city")
	}
}

5. 数组操作

func arrayOperations(rh *rejson.Handler) {
	ctx := context.Background()
	
	// 创建包含数组的JSON
	type Post struct {
		Title   string   `json:"title"`
		Tags    []string `json:"tags"`
		Likes   int      `json:"likes"`
	}
	
	post := Post{
		Title: "Go Redis JSON",
		Tags:  []string{"golang", "redis", "json"},
		Likes: 0,
	}
	
	_, err := rh.JSONSet("post:1", ".", post)
	if err != nil {
		log.Fatalf("Failed to JSONSet post: %v", err)
	}
	
	// 向数组添加元素
	_, err = rh.JSONArrAppend("post:1", ".tags", "database")
	if err != nil {
		log.Fatalf("Failed to append to array: %v", err)
	}
	
	// 获取数组长度
	length, err := rh.JSONArrLen("post:1", ".tags")
	if err != nil {
		log.Fatalf("Failed to get array length: %v", err)
	}
	fmt.Printf("Tags array length: %d\n", length)
	
	// 获取数组元素
	var tags []string
	_, err = rh.JSONGet("post:1", ".tags", &tags)
	if err != nil {
		log.Fatalf("Failed to get tags: %v", err)
	}
	fmt.Printf("Tags: %v\n", tags)
}

6. 删除操作

func deleteOperations(rh *rejson.Handler) {
	ctx := context.Background()
	
	// 删除特定字段
	_, err := rh.JSONDel("user:123", ".address.city")
	if err != nil {
		log.Fatalf("Failed to delete city: %v", err)
	}
	
	// 删除整个JSON对象
	_, err = rh.JSONDel("post:1", ".")
	if err != nil {
		log.Fatalf("Failed to delete post: %v", err)
	}
}

高级特性

1. 批量操作

func batchOperations(rh *rejson.Handler) {
	ctx := context.Background()
	
	// 使用MULTI/EXEC进行批量操作
	pipe := rdb.TxPipeline()
	
	rh.JSONSetWithOptions("user:123", ".", User{Name: "Batch User", Age: 25}, rejson.SetOptions{})
	rh.JSONSetWithOptions("user:123", ".age", 26, rejson.SetOptions{})
	
	_, err := pipe.Exec(ctx)
	if err != nil {
		log.Fatalf("Failed batch operations: %v", err)
	}
}

2. 设置过期时间

func setWithExpire(rh *rejson.Handler) {
	ctx := context.Background()
	
	tempData := map[string]interface{}{
		"token": "abc123",
		"valid": true,
	}
	
	// 设置JSON并添加过期时间
	_, err := rh.JSONSet("temp:session", ".", tempData)
	if err != nil {
		log.Fatalf("Failed to set temp data: %v", err)
	}
	
	// 设置60秒过期
	if err := rdb.Expire(ctx, "temp:session", 60*time.Second).Err(); err != nil {
		log.Fatalf("Failed to set expire: %v", err)
	}
}

最佳实践

  1. 键命名规范:使用冒号分隔的命名空间(如user:123, post:456
  2. 合理使用路径.表示根路径,.field表示特定字段
  3. 错误处理:始终检查返回的错误
  4. 连接池:重用Redis连接以提高性能
  5. 数据结构设计:根据查询模式设计JSON结构

go-rejson提供了强大的功能来操作Redis中的JSON数据,结合Redis的高性能和JSON的灵活性,非常适合需要复杂数据结构和快速访问的场景。

回到顶部