80

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

例如

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 对象,除了手动解析每个字段之外,还有什么方法可以解决这个问题?

4

10 回答 10

129

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

这是示例。

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
于 2013-12-05T12:39:05.483 回答
63

如果您的数据是JSON-serializable,那么这可能是比将 python pickle 保存到外部数据库更好的选择,因为它是 Python 之外更常见的标准,其本身更具可读性,并且避免了相当大的攻击向量.

JSON 示例:

import json
import redis

r = redis.StrictRedis(host='localhost', port=6379, db=0)

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

# Convert python dict to JSON str and save to Redis
json_images = json.dumps(images)
r.set('images', json_images)

# Read saved JSON str from Redis and unpack into python dict
unpacked_images = json.loads(r.get('images'))
images == unpacked_images

蟒蛇3:

unpacked_images = json.loads(r.get('images').decode('utf-8'))
images == unpacked_images
于 2015-09-09T18:01:38.337 回答
56

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

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

于 2013-03-05T09:20:37.803 回答
7

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

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

SubRedis 只是将传递给它的字符串作为前缀添加到平面 redis 数据结构上。我发现这是一个方便的包装模式,我最终在 redis 中做了很多工作——预先添加一些 id 来嵌套一些数据。

于 2014-02-01T02:58:45.670 回答
6

这是一个简单的 Redis 包装器,它可以腌制/取消腌制数据结构:

from redis import Redis
from collections import MutableMapping
from pickle import loads, dumps


class RedisStore(MutableMapping):

    def __init__(self, engine):
        self._store = Redis.from_url(engine)

    def __getitem__(self, key):
        return loads(self._store[dumps(key)])

    def __setitem__(self, key, value):
        self._store[dumps(key)] = dumps(value)

    def __delitem__(self, key):
        del self._store[dumps(key)]

    def __iter__(self):
        return iter(self.keys())

    def __len__(self):
        return len(self._store.keys())

    def keys(self):
        return [loads(x) for x in self._store.keys()]

    def clear(self):
        self._store.flushdb()


d = RedisStore('redis://localhost:6379/0')
d['a'] = {'b': 1, 'c': 10}
print repr(d.items())
# this will not work: (it updates a temporary copy and not the real data)
d['a']['b'] = 2
print repr(d.items())
# this is how to update sub-structures:
t = d['a']
t['b'] = 2
d['a'] = t
print repr(d.items())
del d['a']

# Here is another way to implement dict-of-dict eg d['a']['b']
d[('a', 'b')] = 1
d[('a', 'b')] = 2
print repr(d.items())
# Hopefully you do not need the equivalent of d['a']
print repr([{x[0][1]: x[1]} for x in d.items() if x[0][0] == 'a'])
del d[('a', 'b')]
del d[('a', 'c')]

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

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

于 2018-02-19T17:14:29.413 回答
4

你可以使用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

于 2016-08-30T05:47:31.137 回答
3

您可以将RedisLabs中的 RedisJSON 与用于 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'))
   )
于 2020-05-01T10:15:28.473 回答
0

我最近遇到了类似的用例。在 redis hash 中存储复杂的数据结构。

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

打字稿示例

存储在 hashmap 中的对象

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等价物。

希望这可以帮助。

于 2020-07-08T06:32:55.210 回答
0
 for saving object in redis first convert object into stringify JSON
 StringifyImages = json.dumps(images)
redis.set('images', StringifyImages)

# Read stringify object from redis and parse it 
ParseImages = json.loads(redis.get('images'))
于 2021-10-20T07:55:22.063 回答
-3

您可以按原样存储结构并执行“评估”以将字符串转换为对象:

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
于 2013-03-21T21:43:49.267 回答