问题描述
我想在redis中维护一些元数据.
I want to maintain some meta data in redis.
meta_key = build_key()
meta_data = {
"user": 12345,
"tag": "D12321341234123",
}
res = redis_sip.hmset(meta_key, meta_data)
它按预期工作.
现在我想在这个 meta_data 结构中保留一个列表,并能够将元素添加到列表中.
Now I want to keep a list in this meta_data structure and be able to add element to the list.
例如:
meta_data = {
"user": 12345,
"tag": "D12321341234123",
"items": []
}
但它马上抛出异常:
redis.exceptions.DataError: Invalid input of type: 'list'. Convert to a byte, string or number first.
我认为我可以创建一个新密钥并使用 zadd
来维护一个列表.但是我想尽量减少密钥的数量.这是因为一旦用户退出,我需要快速使密钥无效.将密钥保持在最低限度可以帮助我
I reckon I can create a new key and use zadd
to maintain a list. However I would like to minimise the number of key. It is because I need to quickly invalidate the keys once the user signs out. Keeping the keys to bare minimum can help me to
1) 快速驱逐钥匙
2) 避免错误,因为保持标签的键较少
2) avoid error because there are less keys to keep a tab on
有什么办法可以将列表保留在 redis 值中并轻松扩展列表吗?
Is there any way I can keep a list in a redis value and easily expand the list?
推荐答案
在大多数情况下,SADD
或 ZADD
与流水线命令会更好.如果存在另一个客户端可能在两者之间获取密钥的风险,从而获得不完整的对象,请使用 MULTI/EXEC 事务.
In most cases, SADD
or ZADD
with pipelining commands will be better. Use a MULTI/EXEC transaction if there is risk another client may get the key in between, therefore getting an incomplete object.
在某些情况下,将哈希字段中的列表字符串化可能是合理的.
Stringify the list in a hash-field may be justifiable in a few cases.
关于快速驱逐密钥",请确保使用 UNLINK
而不是 DEL
.
Regarding 'Quickly evict the keys', make sure to use UNLINK
instead of DEL
.
如果您选择字符串化,这里是如何使用 Lua 和 Lua CJSON 库:
If you choose to stringify, here is how to atomically support insert and remove to a JSON-encoded array in a hash field using Lua and Lua CJSON library:
插入:
local items = cjson.decode(redis.call('HGET', KEYS[1], 'items'))
table.insert(items, ARGV[1])
return redis.call('HSET', KEYS[1], 'items', cjson.encode(items))
按值移除:
local items = cjson.decode(redis.call('HGET', KEYS[1], 'items'))
local pos = -1;
for i, v in ipairs(items) do
if ARGV[1] == v then
pos = i
break
end
end
if pos == -1 then
return -1
else
table.remove(items, pos)
return redis.call('HSET', KEYS[1], 'items', cjson.encode(items))
end
使用示例:
> HGETALL meta_key
1) "user"
2) "12345"
3) "tag"
4) "D12321341234123"
5) "items"
6) "{}"
> EVAL "local items = cjson.decode(redis.call('HGET', KEYS[1], 'items')) \n table.insert(items, ARGV[1]) \n return redis.call('HSET', KEYS[1], 'items', cjson.encode(items))" 1 meta_key value1
(integer) 0
> HGETALL meta_key
1) "user"
2) "12345"
3) "tag"
4) "D12321341234123"
5) "items"
6) "[\"value1\"]"
> EVAL "local items = cjson.decode(redis.call('HGET', KEYS[1], 'items')) \n table.insert(items, ARGV[1]) \n return redis.call('HSET', KEYS[1], 'items', cjson.encode(items))" 1 meta_key value2
(integer) 0
> HGETALL meta_key
1) "user"
2) "12345"
3) "tag"
4) "D12321341234123"
5) "items"
6) "[\"value1\",\"value2\"]"
> EVAL "local items = cjson.decode(redis.call('HGET', KEYS[1], 'items')) \n local pos = -1; \n for i, v in ipairs(items) do \n if ARGV[1] == v then \n pos = i \n break \n end \n end \n if pos == -1 then \n return -1 \n else \n table.remove(items, pos) \n return redis.call('HSET', KEYS[1], 'items', cjson.encode(items)) \n end" 1 meta_key value1
(integer) 0
> HGETALL meta_key
1) "user"
2) "12345"
3) "tag"
4) "D12321341234123"
5) "items"
6) "[\"value2\"]"
> EVAL "local items = cjson.decode(redis.call('HGET', KEYS[1], 'items')) \n local pos = -1; \n for i, v in ipairs(items) do \n if ARGV[1] == v then \n pos = i \n break \n end \n end \n if pos == -1 then \n return -1 \n else \n table.remove(items, pos) \n return redis.call('HSET', KEYS[1], 'items', cjson.encode(items)) \n end" 1 meta_key value3
(integer) -1
> HGETALL meta_key
1) "user"
2) "12345"
3) "tag"
4) "D12321341234123"
5) "items"
6) "[\"value2\"]"
这篇关于如何将列表嵌套到Redis中的结构中以减少顶级?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!