How to store and retrieve a dictionary with redis
Question:
# I have the dictionary my_dict
my_dict = {
'var1' : 5
'var2' : 9
}
r = redis.StrictRedis()
How would I store my_dict and retrieve it with redis. For example, the following code does not work.
#Code that doesn't work
r.set('this_dict', my_dict) # to store my_dict in this_dict
r.get('this_dict') # to retrieve my_dict
Answers:
The redis SET command stores a string, not arbitrary data. You could try using the redis HSET command to store the dict as a redis hash with something like
for k,v in my_dict.iteritems():
r.hset('my_dict', k, v)
but the redis datatypes and python datatypes don’t quite line up. Python dicts can be arbitrarily nested, but a redis hash is going to require that your value is a string. Another approach you can take is to convert your python data to string and store that in redis, something like
r.set('this_dict', str(my_dict))
and then when you get the string out you will need to parse it to recreate the python object.
you can pickle your dict and save as string.
import pickle
import redis
r = redis.StrictRedis('localhost')
mydict = {1:2,2:3,3:4}
p_mydict = pickle.dumps(mydict)
r.set('mydict',p_mydict)
read_dict = r.get('mydict')
yourdict = pickle.loads(read_dict)
You can do it by hmset
(multiple keys can be set using hmset
).
hmset("RedisKey", dictionaryToSet)
import redis
conn = redis.Redis('localhost')
user = {"Name":"Pradeep", "Company":"SCTL", "Address":"Mumbai", "Location":"RCP"}
conn.hmset("pythonDict", user)
conn.hgetall("pythonDict")
{'Company': 'SCTL', 'Address': 'Mumbai', 'Location': 'RCP', 'Name': 'Pradeep'}
Another way: you can use RedisWorks
library.
pip install redisworks
>>> from redisworks import Root
>>> root = Root()
>>> root.something = {1:"a", "b": {2: 2}} # saves it as Hash type in Redis
...
>>> print(root.something) # loads it from Redis
{'b': {2: 2}, 1: 'a'}
>>> root.something['b'][2]
2
It converts python types to Redis types and vice-versa.
>>> root.sides = [10, [1, 2]] # saves it as list in Redis.
>>> print(root.sides) # loads it from Redis
[10, [1, 2]]
>>> type(root.sides[1])
<class 'list'>
Disclaimer: I wrote the library. Here is the code: https://github.com/seperman/redisworks
If you want to store a python dict in redis, it is better to store it as json string.
import json
import redis
r = redis.StrictRedis(host='localhost', port=6379, db=0)
mydict = { 'var1' : 5, 'var2' : 9, 'var3': [1, 5, 9] }
rval = json.dumps(mydict)
r.set('key1', rval)
While retrieving de-serialize it using json.loads
data = r.get('key1')
result = json.loads(data)
arr = result['var3']
What about types (eg.bytes) that are not serialized by json functions ?
You can write encoder/decoder functions for types that cannot be serialized by json functions. eg. writing base64/ascii encoder/decoder function for byte array.
As the basic answer has already give by other people, I would like to add some to it.
Following are the commands in REDIS
to perform basic operations with HashMap/Dictionary/Mapping
type values.
- HGET => Returns value for single key passed
- HSET => set/updates value for the single key
- HMGET => Returns value for single/multiple keys passed
- HMSET => set/updates values for the multiple key
- HGETALL => Returns all the (key, value) pairs in the mapping.
Following are their respective methods in redis-py
library :-
- HGET => hget
- HSET => hset
- HMGET => hmget
- HMSET => hmset
- HGETALL => hgetall
All of the above setter methods creates the mapping, if it doesn’t exists.
All of the above getter methods doesn’t raise error/exceptions, if mapping/key in mapping doesn’t exists.
Example:
=======
In [98]: import redis
In [99]: conn = redis.Redis('localhost')
In [100]: user = {"Name":"Pradeep", "Company":"SCTL", "Address":"Mumbai", "Location":"RCP"}
In [101]: con.hmset("pythonDict", {"Location": "Ahmedabad"})
Out[101]: True
In [102]: con.hgetall("pythonDict")
Out[102]:
{b'Address': b'Mumbai',
b'Company': b'SCTL',
b'Last Name': b'Rajpurohit',
b'Location': b'Ahmedabad',
b'Name': b'Mangu Singh'}
In [103]: con.hmset("pythonDict", {"Location": "Ahmedabad", "Company": ["A/C Pri
...: sm", "ECW", "Musikaar"]})
Out[103]: True
In [104]: con.hgetall("pythonDict")
Out[104]:
{b'Address': b'Mumbai',
b'Company': b"['A/C Prism', 'ECW', 'Musikaar']",
b'Last Name': b'Rajpurohit',
b'Location': b'Ahmedabad',
b'Name': b'Mangu Singh'}
In [105]: con.hget("pythonDict", "Name")
Out[105]: b'Mangu Singh'
In [106]: con.hmget("pythonDict", "Name", "Location")
Out[106]: [b'Mangu Singh', b'Ahmedabad']
I hope, it makes things more clear.
Try rejson-py which is relatively new since 2017. Look at this introduction.
from rejson import Client, Path
rj = Client(host='localhost', port=6379)
# Set the key `obj` to some object
obj = {
'answer': 42,
'arr': [None, True, 3.14],
'truth': {
'coord': 'out there'
}
}
rj.jsonset('obj', Path.rootPath(), obj)
# Get something
print 'Is there anybody... {}?'.format(
rj.jsonget('obj', Path('.truth.coord'))
)
# Delete something (or perhaps nothing), append something and pop it
rj.jsondel('obj', Path('.arr[0]'))
rj.jsonarrappend('obj', Path('.arr'), 'something')
print '{} popped!'.format(rj.jsonarrpop('obj', Path('.arr')))
# Update something else
rj.jsonset('obj', Path('.answer'), 2.17)
An other way you can approach the matter:
import redis
conn = redis.Redis('localhost')
v={'class':'user','grants': 0, 'nome': 'Roberto', 'cognome': 'Brunialti'}
y=str(v)
print(y['nome']) #<=== this return an error as y is actually a string
conn.set('test',y)
z=eval(conn.get('test'))
print(z['nome']) #<=== this really works!
I did not test it for efficiency/speed.
If you don’t know exactly how to organize data in Redis, I did some performance tests, including the results parsing.
The dictonary I used (d) had 437.084 keys (md5 format), and the values of this form:
{"path": "G:tests2687.3575.json",
"info": {"f": "foo", "b": "bar"},
"score": 2.5}
First Test (inserting data into a redis key-value mapping):
conn.hmset('my_dict', d) # 437.084 keys added in 8.98s
conn.info()['used_memory_human'] # 166.94 Mb
for key in d:
json.loads(conn.hget('my_dict', key).decode('utf-8').replace("'", '"'))
# 41.1 s
import ast
for key in d:
ast.literal_eval(conn.hget('my_dict', key).decode('utf-8'))
# 1min 3s
conn.delete('my_dict') # 526 ms
Second Test (inserting data directly into Redis keys):
for key in d:
conn.hmset(key, d[key]) # 437.084 keys added in 1min 20s
conn.info()['used_memory_human'] # 326.22 Mb
for key in d:
json.loads(conn.hgetall(key)[b'info'].decode('utf-8').replace("'", '"'))
# 1min 11s
for key in d:
conn.delete(key)
# 37.3s
As you can see, in the second test, only ‘info’ values have to be parsed, because the hgetall(key) already returns a dict, but not a nested one.
And of course, the best example of using Redis as python’s dicts, is the First Test
One might consider using MessagePack which is endorsed by redis.
import msgpack
data = {
'one': 'one',
'two': 2,
'three': [1, 2, 3]
}
await redis.set('my-key', msgpack.packb(data))
val = await redis.get('my-key')
print(msgpack.unpackb(val))
# {'one': 'one', 'two': 2, 'three': [1, 2, 3]}
Using msgpack-python and aioredis
HMSET is deprecated per the Redis docs. You can now use HSET
with a dictionary as follows:
import redis
r = redis.Redis('localhost')
key = "hashexample"
entry = {
"version":"1.2.3",
"tag":"main",
"status":"CREATED",
"timeout":"30"
}
r.hset(key, mapping=entry)
Caution: very unintuitively, hset
won’t accept a dictionary (raising an error suggesting it does not accept dictionaries, see [1]) if it is simply passed to the 2nd positional (unnamed) argument. You need to pass the dictionary to a named argument mapping=
.
[1] *** redis.exceptions.DataError: Invalid input of type: 'dict'. Convert to a bytes, string, int or float first.
DeprecationWarning: Redis.hmset() is deprecated. Use Redis.hset() instead.
Since HMSET is deprecated you can use HSET:
import redis
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
r.hset('user:23', mapping={'id': 23, 'name': 'ip'})
r.hgetall('user:23')
In the context of Nameko (Python microservices framework which frequently uses a redis backend) you can use hmset as follows:
import uuid
from nameko.rpc import rpc
from nameko_redis import Redis
class AirportsService:
name = "trips_service"
redis = Redis('development')
@rpc
def get(self, trip_id):
trip = self.redis.get(trip_id)
return trip
@rpc
def create(self, airport_from_id, airport_to_id):
trip_id = uuid.uuid4().hex
pyDict = {"from":airport_from_id, "to":airport_to_id}
self.redis.hmset(trip_id, pyDict)
return trip_id
Lots of good answers but this worked for me.
- store dictionary
- get dictionary
- nested hash instead of mapping the dict as key to field and value to value like other answers above. (see example 1)
- get all field/values and go from there as normally you would in a project where you want to dump a dict to a redis hash where the dict is a nested hash. (see example 2)
note: these commands were done in the python repl
- if you want
{'field1': 'Hello', 'field2': 'World'}
Use
r = redis.Redis(host="localhost", port=6379, db=0, decode_responses=True)
pdict = {'field1': 'Hello', 'field2': 'World'}
r.hmset("queues_test", pdict)
Also refer to other answers, particularly Saji Xavier’s since its simple and works.
If you want a nested hash like
{'queue1': '{"field1": "Hello", "field2": "World"}'
then
# to set
import json
r = redis.Redis(host="localhost", port=6379, db=0, decode_responses=True)
pdict = {'field1': 'Hello', 'field2': 'World'}
pdict_string = json.dumps(pdict)
r.hset("queues_data", "queue1", pdict_string)
# to get a single field value
r.hget("queues_data", "queue1")
# '{"field1": "Hello", "field2": "World"}'
# to get all fields
data = r.hgetall("queues_data")
# {'queue1': '{"field1": "Hello", "field2": "World"}'
queue1 = data['queue1']
queue1
# '{"field1": "Hello", "field2": "World"}'
result = json.loads(queue1)
result
# {'field1': 'Hello', 'field2': 'World'}
result['field1']
# 'Hello'
Then if you just need the keys/values
list(data.keys())
# ['queue1', 'queue2']
list(data.values())
# ['{"field1": "Hello", "field2": "World"}', '{"field1": "Hello", "field2": "World"}']
Then if you want get the dict back for all values in one line use
lvalues = list(data.values())
# ['{"field1": "Hello", "field2": "World"}', '{"field1": "Hello", "field2": "World"}']
[json.loads(x) for x in lvalues]
# [{'field1': 'Hello', 'field2': 'World'}, {'field1': 'Hello', 'field2': 'World'}]
# I have the dictionary my_dict
my_dict = {
'var1' : 5
'var2' : 9
}
r = redis.StrictRedis()
How would I store my_dict and retrieve it with redis. For example, the following code does not work.
#Code that doesn't work
r.set('this_dict', my_dict) # to store my_dict in this_dict
r.get('this_dict') # to retrieve my_dict
The redis SET command stores a string, not arbitrary data. You could try using the redis HSET command to store the dict as a redis hash with something like
for k,v in my_dict.iteritems():
r.hset('my_dict', k, v)
but the redis datatypes and python datatypes don’t quite line up. Python dicts can be arbitrarily nested, but a redis hash is going to require that your value is a string. Another approach you can take is to convert your python data to string and store that in redis, something like
r.set('this_dict', str(my_dict))
and then when you get the string out you will need to parse it to recreate the python object.
you can pickle your dict and save as string.
import pickle
import redis
r = redis.StrictRedis('localhost')
mydict = {1:2,2:3,3:4}
p_mydict = pickle.dumps(mydict)
r.set('mydict',p_mydict)
read_dict = r.get('mydict')
yourdict = pickle.loads(read_dict)
You can do it by hmset
(multiple keys can be set using hmset
).
hmset("RedisKey", dictionaryToSet)
import redis
conn = redis.Redis('localhost')
user = {"Name":"Pradeep", "Company":"SCTL", "Address":"Mumbai", "Location":"RCP"}
conn.hmset("pythonDict", user)
conn.hgetall("pythonDict")
{'Company': 'SCTL', 'Address': 'Mumbai', 'Location': 'RCP', 'Name': 'Pradeep'}
Another way: you can use RedisWorks
library.
pip install redisworks
>>> from redisworks import Root
>>> root = Root()
>>> root.something = {1:"a", "b": {2: 2}} # saves it as Hash type in Redis
...
>>> print(root.something) # loads it from Redis
{'b': {2: 2}, 1: 'a'}
>>> root.something['b'][2]
2
It converts python types to Redis types and vice-versa.
>>> root.sides = [10, [1, 2]] # saves it as list in Redis.
>>> print(root.sides) # loads it from Redis
[10, [1, 2]]
>>> type(root.sides[1])
<class 'list'>
Disclaimer: I wrote the library. Here is the code: https://github.com/seperman/redisworks
If you want to store a python dict in redis, it is better to store it as json string.
import json
import redis
r = redis.StrictRedis(host='localhost', port=6379, db=0)
mydict = { 'var1' : 5, 'var2' : 9, 'var3': [1, 5, 9] }
rval = json.dumps(mydict)
r.set('key1', rval)
While retrieving de-serialize it using json.loads
data = r.get('key1')
result = json.loads(data)
arr = result['var3']
What about types (eg.bytes) that are not serialized by json functions ?
You can write encoder/decoder functions for types that cannot be serialized by json functions. eg. writing base64/ascii encoder/decoder function for byte array.
As the basic answer has already give by other people, I would like to add some to it.
Following are the commands in REDIS
to perform basic operations with HashMap/Dictionary/Mapping
type values.
- HGET => Returns value for single key passed
- HSET => set/updates value for the single key
- HMGET => Returns value for single/multiple keys passed
- HMSET => set/updates values for the multiple key
- HGETALL => Returns all the (key, value) pairs in the mapping.
Following are their respective methods in redis-py
library :-
- HGET => hget
- HSET => hset
- HMGET => hmget
- HMSET => hmset
- HGETALL => hgetall
All of the above setter methods creates the mapping, if it doesn’t exists.
All of the above getter methods doesn’t raise error/exceptions, if mapping/key in mapping doesn’t exists.
Example:
=======
In [98]: import redis
In [99]: conn = redis.Redis('localhost')
In [100]: user = {"Name":"Pradeep", "Company":"SCTL", "Address":"Mumbai", "Location":"RCP"}
In [101]: con.hmset("pythonDict", {"Location": "Ahmedabad"})
Out[101]: True
In [102]: con.hgetall("pythonDict")
Out[102]:
{b'Address': b'Mumbai',
b'Company': b'SCTL',
b'Last Name': b'Rajpurohit',
b'Location': b'Ahmedabad',
b'Name': b'Mangu Singh'}
In [103]: con.hmset("pythonDict", {"Location": "Ahmedabad", "Company": ["A/C Pri
...: sm", "ECW", "Musikaar"]})
Out[103]: True
In [104]: con.hgetall("pythonDict")
Out[104]:
{b'Address': b'Mumbai',
b'Company': b"['A/C Prism', 'ECW', 'Musikaar']",
b'Last Name': b'Rajpurohit',
b'Location': b'Ahmedabad',
b'Name': b'Mangu Singh'}
In [105]: con.hget("pythonDict", "Name")
Out[105]: b'Mangu Singh'
In [106]: con.hmget("pythonDict", "Name", "Location")
Out[106]: [b'Mangu Singh', b'Ahmedabad']
I hope, it makes things more clear.
Try rejson-py which is relatively new since 2017. Look at this introduction.
from rejson import Client, Path
rj = Client(host='localhost', port=6379)
# Set the key `obj` to some object
obj = {
'answer': 42,
'arr': [None, True, 3.14],
'truth': {
'coord': 'out there'
}
}
rj.jsonset('obj', Path.rootPath(), obj)
# Get something
print 'Is there anybody... {}?'.format(
rj.jsonget('obj', Path('.truth.coord'))
)
# Delete something (or perhaps nothing), append something and pop it
rj.jsondel('obj', Path('.arr[0]'))
rj.jsonarrappend('obj', Path('.arr'), 'something')
print '{} popped!'.format(rj.jsonarrpop('obj', Path('.arr')))
# Update something else
rj.jsonset('obj', Path('.answer'), 2.17)
An other way you can approach the matter:
import redis
conn = redis.Redis('localhost')
v={'class':'user','grants': 0, 'nome': 'Roberto', 'cognome': 'Brunialti'}
y=str(v)
print(y['nome']) #<=== this return an error as y is actually a string
conn.set('test',y)
z=eval(conn.get('test'))
print(z['nome']) #<=== this really works!
I did not test it for efficiency/speed.
If you don’t know exactly how to organize data in Redis, I did some performance tests, including the results parsing.
The dictonary I used (d) had 437.084 keys (md5 format), and the values of this form:
{"path": "G:tests2687.3575.json",
"info": {"f": "foo", "b": "bar"},
"score": 2.5}
First Test (inserting data into a redis key-value mapping):
conn.hmset('my_dict', d) # 437.084 keys added in 8.98s
conn.info()['used_memory_human'] # 166.94 Mb
for key in d:
json.loads(conn.hget('my_dict', key).decode('utf-8').replace("'", '"'))
# 41.1 s
import ast
for key in d:
ast.literal_eval(conn.hget('my_dict', key).decode('utf-8'))
# 1min 3s
conn.delete('my_dict') # 526 ms
Second Test (inserting data directly into Redis keys):
for key in d:
conn.hmset(key, d[key]) # 437.084 keys added in 1min 20s
conn.info()['used_memory_human'] # 326.22 Mb
for key in d:
json.loads(conn.hgetall(key)[b'info'].decode('utf-8').replace("'", '"'))
# 1min 11s
for key in d:
conn.delete(key)
# 37.3s
As you can see, in the second test, only ‘info’ values have to be parsed, because the hgetall(key) already returns a dict, but not a nested one.
And of course, the best example of using Redis as python’s dicts, is the First Test
One might consider using MessagePack which is endorsed by redis.
import msgpack
data = {
'one': 'one',
'two': 2,
'three': [1, 2, 3]
}
await redis.set('my-key', msgpack.packb(data))
val = await redis.get('my-key')
print(msgpack.unpackb(val))
# {'one': 'one', 'two': 2, 'three': [1, 2, 3]}
Using msgpack-python and aioredis
HMSET is deprecated per the Redis docs. You can now use HSET
with a dictionary as follows:
import redis
r = redis.Redis('localhost')
key = "hashexample"
entry = {
"version":"1.2.3",
"tag":"main",
"status":"CREATED",
"timeout":"30"
}
r.hset(key, mapping=entry)
Caution: very unintuitively, hset
won’t accept a dictionary (raising an error suggesting it does not accept dictionaries, see [1]) if it is simply passed to the 2nd positional (unnamed) argument. You need to pass the dictionary to a named argument mapping=
.
[1] *** redis.exceptions.DataError: Invalid input of type: 'dict'. Convert to a bytes, string, int or float first.
DeprecationWarning: Redis.hmset() is deprecated. Use Redis.hset() instead.
Since HMSET is deprecated you can use HSET:
import redis
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
r.hset('user:23', mapping={'id': 23, 'name': 'ip'})
r.hgetall('user:23')
In the context of Nameko (Python microservices framework which frequently uses a redis backend) you can use hmset as follows:
import uuid
from nameko.rpc import rpc
from nameko_redis import Redis
class AirportsService:
name = "trips_service"
redis = Redis('development')
@rpc
def get(self, trip_id):
trip = self.redis.get(trip_id)
return trip
@rpc
def create(self, airport_from_id, airport_to_id):
trip_id = uuid.uuid4().hex
pyDict = {"from":airport_from_id, "to":airport_to_id}
self.redis.hmset(trip_id, pyDict)
return trip_id
Lots of good answers but this worked for me.
- store dictionary
- get dictionary
- nested hash instead of mapping the dict as key to field and value to value like other answers above. (see example 1)
- get all field/values and go from there as normally you would in a project where you want to dump a dict to a redis hash where the dict is a nested hash. (see example 2)
note: these commands were done in the python repl
- if you want
{'field1': 'Hello', 'field2': 'World'}
Use
r = redis.Redis(host="localhost", port=6379, db=0, decode_responses=True)
pdict = {'field1': 'Hello', 'field2': 'World'}
r.hmset("queues_test", pdict)
Also refer to other answers, particularly Saji Xavier’s since its simple and works.
If you want a nested hash like
{'queue1': '{"field1": "Hello", "field2": "World"}'
then
# to set
import json
r = redis.Redis(host="localhost", port=6379, db=0, decode_responses=True)
pdict = {'field1': 'Hello', 'field2': 'World'}
pdict_string = json.dumps(pdict)
r.hset("queues_data", "queue1", pdict_string)
# to get a single field value
r.hget("queues_data", "queue1")
# '{"field1": "Hello", "field2": "World"}'
# to get all fields
data = r.hgetall("queues_data")
# {'queue1': '{"field1": "Hello", "field2": "World"}'
queue1 = data['queue1']
queue1
# '{"field1": "Hello", "field2": "World"}'
result = json.loads(queue1)
result
# {'field1': 'Hello', 'field2': 'World'}
result['field1']
# 'Hello'
Then if you just need the keys/values
list(data.keys())
# ['queue1', 'queue2']
list(data.values())
# ['{"field1": "Hello", "field2": "World"}', '{"field1": "Hello", "field2": "World"}']
Then if you want get the dict back for all values in one line use
lvalues = list(data.values())
# ['{"field1": "Hello", "field2": "World"}', '{"field1": "Hello", "field2": "World"}']
[json.loads(x) for x in lvalues]
# [{'field1': 'Hello', 'field2': 'World'}, {'field1': 'Hello', 'field2': 'World'}]