{"id":15170954,"url":"https://github.com/nitishm/rejson-struct","last_synced_at":"2025-10-25T21:31:39.205Z","repository":{"id":98331050,"uuid":"133294271","full_name":"nitishm/rejson-struct","owner":"nitishm","description":"Storing golang structs in redis using rejson module","archived":false,"fork":false,"pushed_at":"2018-05-17T01:15:35.000Z","size":37,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-31T10:36:10.952Z","etag":null,"topics":["go","golang","json","redis","redislabs","rejson"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nitishm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-05-14T02:24:13.000Z","updated_at":"2025-01-08T09:56:55.000Z","dependencies_parsed_at":null,"dependency_job_id":"4d4dfdfa-bad5-4a71-83ce-8ebea2aeb636","html_url":"https://github.com/nitishm/rejson-struct","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitishm%2Frejson-struct","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitishm%2Frejson-struct/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitishm%2Frejson-struct/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitishm%2Frejson-struct/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nitishm","download_url":"https://codeload.github.com/nitishm/rejson-struct/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238212407,"owners_count":19434955,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","json","redis","redislabs","rejson"],"created_at":"2024-09-27T08:42:15.096Z","updated_at":"2025-10-25T21:31:33.937Z","avatar_url":"https://github.com/nitishm.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Using Redis HMSET versus RedisLab's ReJSON for golang objects\n\nCheck out my Medium post about chosing ReJSON for storing Go Structs at https://medium.com/@nitishmalhotra/storing-go-structs-in-redis-using-rejson-dab7f8fc0053\n\n---\n\nIn this example I present an alternative way to use Redis to store (embedded) structs like -\n```golang\ntype Student struct {\n\tInfo *StudentDetails\n\tRank int            \n}\n\ntype StudentDetails struct {\n\tFirstName string\n\tLastName  string\n\tMajor     string\n}\n```\n\n## Why can't we just use [Redigo](https://github.com/gomodule/redigo) ?\nI have used [redigo](https://github.com/gomodule/redigo), for the past year, to interact with Redis and absolutely love the library.\nHowever the biggest problem I face is when working with embedded structs. Redigo works fine if we stick to standard data types and avoid embedded struct. The [`HMSET`](https://redis.io/commands/hmset) arguments can be used in conjuction with `redis.Args{key}.AddFlat(value)...` to flatten a data-structure to be stored in Redis. The data can be read back on an [`HGETALL`](https://redis.io/commands/hgetall) using the helper `redis.ScanStruct(value, \u0026obj)`.\n\nThe problem arises when this is used with an embedded struct instance. The resulting data stored in Redis looks like below - \n\n\u003e [Key] Info - [Value] \u0026{John Doe CSE} [Type string]\n\nWhen the data is read back into the structure using `redis.ScanStruct(value, \u0026student)`, it fails to port the data into the embedded object, and returns an **error**.\n\n# Solution#1\n## JSON Marshal\nA way of getting around this is to store the object as a JSON string. \n\nAdd the object to the DB using :\n\n```golang\n// Add it into Redis against the JSON field (This can be done with a regular SET as well) \nb, err := json.Marshal(value)\nif err != nil {\n\treturn\n}\n_, err = conn.Do(\"HSET\", key, \"JSON\", string(b))\nif err != nil {\n\treturn\n}\n\n// Read it from Redis and Unmarshal back into the struct \ns, err := redis.String(conn.Do(\"HGET\", key, \"JSON\"))\nif err != nil {\n\treturn\n}\n\nerr = json.Unmarshal([]byte(s), res)\nif err != nil {\n\treturn\n}\n```\n\nThis works well if all you need to do is cache the entire object and not worry about ever accessing or modifying the individual members of the object.\n\nHowever, if you wish to read / modify the fields in the object you will have to Unmarshal the object, modify the field and then re-add the object back into Redis.\n\n# Solution#2\n## [ReJSON](https://github.com/RedisLabsModules/ReJSON/)\nWith `ReJSON` you can instead store the object into Redis directly as a JSON object (mind you not Marshaled as JSON string). The object is added to Redis using the [`JSON.SET`](http://rejson.io/commands/#jsonset) command. The best part is that we can now `GET` any part of our JSON object back from Redis using the [`JSON.GET`](http://rejson.io/commands/#jsondel) and specifying the path to the member field.\n\nTo add the object into Redis using the ReJSON module I use [go-rejson](https://github.com/nitishm/go-rejson), a helper library that I wrote to easily use the commands with redigo.\n\n```golang\n// func JSONSet(conn redis.Conn, key string, path string, obj interface{}, NX bool, XX bool) (res interface{}, err error)\n_, err = rejson.JSONSet(conn, key, \"\", value, false, false)\nif err != nil {\n\treturn\n}\nreturn\n```\n\nAnd each field in the object can be read using :\n```golang\n// func JSONGet(conn redis.Conn, key string, path string) (res interface{}, err error)\nres, err := rejson.JSONGet(conn, key, path)\nif err != nil {\n\treturn\n}\n```\n\nThere is a whole bunch of documentation around using the ReJSON module available at [rejson.io](http://rejson.io/).\n\n# Example\n## Running\n### Docker\nRun the docker container provided by ReJSON as follows,\n\n```\ndocker run -p 6379:6379 --name redis-rejson redislabs/rejson:latest\n```\n\nOnce the container has spun up, run the `main.go` by performing,\n\n```\ngo run main.go\n```\n\n## Output\nRunning the example would generate the entries shown below : \n```\n127.0.0.1:6379\u003e keys *\n1) \"JohnDoeJSON\"\n2) \"JohnDoeHashJSON\"\n3) \"JohnDoeHash\"\n```\n\n**Re-JSON (with pretty print options)**\n```\n127.0.0.1:6379\u003e JSON.GET JohnDoeJSON INDENT \"\\t\" NEWLINE \"\\n\" SPACE \" \"\n{\n        \"info\": {\n                \"FirstName\": \"John\",\n                \"LastName\": \"Doe\",\n                \"Major\": \"CSE\"\n        },\n        \"rank\": 1\n}\n```\n\n**HGETALL with key/value pair in odd/even numbers**\n```\n127.0.0.1:6379\u003e HGETALL JohnDoeHash\nInfo\n\u0026{John Doe CSE}\nRank\n1\n```\n\n**HGETALL (stored as JSON)**\n```\n127.0.0.1:6379\u003e HGETALL JohnDoeHashJSON\nJSON\n{\"info\":{\"FirstName\":\"John\",\"LastName\":\"Doe\",\"Major\":\"CSE\"},\"rank\":1}\n```\n\n# The fancy bits\n## Getting an object field using ReJSON\n```\n127.0.0.1:6379\u003e JSON.GET JohnDoeJSON INDENT \"\\t\" NEWLINE \"\\n\" SPACE \" \" .info\n{\n        \"FirstName\": \"John\",\n        \"LastName\": \"Doe\",\n        \"Major\": \"CSE\"\n}\n```\n\n## Setting an object field using ReJSON\n```\n127.0.0.1:6379\u003e JSON.SET JohnDoeJSON info.Major '\"EEE\"'\nOK\n\n127.0.0.1:6379\u003e JSON.GET JohnDoeJSON INDENT \"\\t\" NEWLINE \"\\n\" SPACE \" \" .info\n{\n        \"FirstName\": \"John\",\n        \"LastName\": \"Doe\",\n        \"Major\": \"EEE\"\n}\n```\n\n# Running the example\n## Launching Redis with ReJSON module\n```\ndocker run -p 6379:6379 --name redis-rejson redislabs/rejson:latest\n```\n\n## Running the code\n```\ngit clone https://github.com/nitishm/rejson-struct.git\ncd rejson-struct\ngo run main.go\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnitishm%2Frejson-struct","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnitishm%2Frejson-struct","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnitishm%2Frejson-struct/lists"}