如何在redis中存储复杂对象(使用redis-py)

时间:2013-03-05 09:14:15

标签: python redis

hmset函数可以设置每个字段的值,但我发现如果值本身是一个复杂的结构化对象,则从hget返回的值是序列化字符串,而不是原始对象

e.g

images= [{'type':'big', 'url':'....'},
     {'type':'big', 'url':'....'},
     {'type':'big', 'url':'....'}]   

redis = Redis()
redis.hset('photo:1', 'images', images)

i = redis.hget('photo:1', 'images')
print type(i)

i的类型是字符串,而不是python对象,除了手动解析每个字段之外,还有什么方法可以解决这个问题吗?

8 个答案:

答案 0 :(得分:74)

实际上,您可以使用内置模块pickle在redis中存储python对象。

这是一个例子。

import pickle
import redis

r = redis.StrictRedis(host='localhost', port=6379, db=0)
obj = ExampleObject()
pickled_object = pickle.dumps(obj)
r.set('some_key', pickled_object)
unpacked_object = pickle.loads(r.get('some_key'))
obj == unpacked_object

答案 1 :(得分:44)

您无法在Redis中创建嵌套结构,这意味着您无法(例如)将本机redis列表存储在本机redis哈希映射中。

如果你真的需要嵌套结构,你可能只想存储一个JSON-blob(或类似的东西)。另一种选择是将“id”/键存储到不同的redis对象作为映射键的值,但这需要多次调用服务器才能获得完整的对象。

答案 2 :(得分:5)

我创建了一个库SubRedis,它允许您在redis中创建更复杂的结构/层次结构。如果你给它一个redis实例和一个前缀,它会给你一个几乎完全能力和独立的redis实例。

redis = Redis()
photoRedis = SubRedis("photo:%s" % photoId, redis)
photoRedis.hmset('image0', images[0])
photoRedis.hmset('image1', images[1])
...

SubRedis最终将传入其中的字符串作为前缀添加到flat redis数据结构中。我发现这是一个方便的模式包装器,我最终在redis中做了很多 - 在一些id之前加上一些数据。

答案 3 :(得分:3)

您可以使用RedisWorks库。

pip install redisworks

>>> from redisworks import Root
>>> root = Root()
>>> root.something = {1:"a", "b": {2: 2}}  # saves it as Hash
>>> print(root.something)  # loads it from Redis
{'b': {2: 2}, 1: 'a'}
>>> root.something['b'][2]
2

它将python类型转换为Redis类型,反之亦然。

>>> 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'>

免责声明:我写了这个库。以下是代码:https://github.com/seperman/redisworks

答案 4 :(得分:3)

这是一个围绕Redis的简单包装器,用于pickle / unpickles数据结构:

file = open("text.txt","a")
n=0
while n<=5:
 y = str(input("name: "))
 x = int(input("marks: "))
 result = "Pass"
 if x<35:
    result = "Fail"
    print(y,result)
 file.write('"{}#{}"/n', format(y,result))
 elif 35<=x<=54:
    result = "S"
    print(y,result)
 file.write('"{}#{}"/n', format(y,result))
 elif 55<=x<=64:
    result = "C"
    print(y,result)
 file.write('"{}#{}"/n', format(y,result))
 elif 65<=x<=74:
    result = "B"
    print(y,result)
 file.write('"{}#{}"/n', format(y,result))
 elif (75<=x<=100):
    result = "A"
    print(y,result)
 file.write('"{}#{}"/n', format(y,result))
 else:
    print ("Invalid Enter")
 n = n+1
file.close

如果你更喜欢redis中的纯文本可读数据(pickle存储它的二进制版本),你可以用repr和pickle.loads替换pickle.dump和ast.literal_eval。对于json,请使用json.dumps和json.loads。

如果您始终使用简单字符串的键,则可以从键中删除酸洗。

答案 5 :(得分:2)

您可以将RedisLabs中的RedisJSONclient for python一起使用。 它支持嵌套数据结构。对于这样的任务非常有用。

示例中的一些代码:

   # 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'))
   )

答案 6 :(得分:0)

我最近也遇到过类似的用例。在redis哈希中存储复杂的数据结构。

我认为解决此问题的最佳方法是将json对象序列化为字符串并将其存储为另一个对象的值。

打字稿示例

要存储在哈希图中的对象

const payload = {
 "k1":"v1",
 "k2": "v2",
 "k3": {
     "k4":"v4",
     "k5":"v5"
  }
}

将此有效负载存储为

await redis.hmset('hashMapKey', {somePayloadKey: JSON.stringify(payload) });

可以将其检索为

      const result = await redis.hgetall('hashMapKey');
      const payload = JSON.parse(result.somePayloadKey);

hmset和hgetall与redis中的HMSET和HGETALL等效,tedis

希望这会有所帮助。

答案 7 :(得分:-1)

您可以按原样存储结构,并执行'eval'以从String转换为Object:

images= [{'type':'big', 'url':'....'},
 {'type':'big', 'url':'....'},
 {'type':'big', 'url':'....'}]   
redis = Redis()
redis.hset('photo:1', 'images', images)

i = eval(redis.hget('photo:1', 'images'))
print type(i) #type of i should be list instead of string now