仅当Redis列表中的值尚不存在时才将其添加到Redis列表中?

时间:2013-05-18 06:53:48

标签: redis

我正在尝试向列表添加值,但仅限于尚未添加的值。

是否有命令执行此操作或有没有办法测试列表中是否存在值?

谢谢!

7 个答案:

答案 0 :(得分:8)

我需要做同样的事情。 我想从列表中删除元素然后再添加它。如果元素不在列表中,redis将返回0,因此没有错误

lrem mylist 0 myitem
rpush mylist myitem 

答案 1 :(得分:4)

正如Tommaso Barbugli所提到的,如果您只需要唯一值,则应使用集合而不是列表。 see REDIS documentation SADD

redis>  SADD myset "Hello"
(integer) 1
redis>  SADD myset "World"
(integer) 1
redis>  SADD myset "World"
(integer) 0
redis>  SMEMBERS myset
1) "World"
2) "Hello"

如果要检查集合中是否存在值,可以使用SISMEMBER

redis>  SADD myset "one"
(integer) 1
redis>  SISMEMBER myset "one"
(integer) 1
redis>  SISMEMBER myset "two"
(integer) 0

答案 2 :(得分:2)

看起来你需要一套或一组排序。

集合具有O(1)成员资格测试和强制唯一性。

答案 3 :(得分:1)

使用redis中的hexists hexists命令在集合中可以使用此功能。

答案 4 :(得分:1)

检查列表以查看其中是否存在成员是O(n),这对于大型列表来说可能会非常昂贵,并且绝对不是理想的。也就是说,其他人似乎都在为您提供替代方案。我只会告诉你如何做你要做的事情,并假设你有充分的理由按照你的方式去做。我将在Python中执行此操作,假设您与Redis有r的连接,一些名为some_list的列表和一些要添加的新项目new_item

lst = r.lrange(list_name, -float('Inf'), float('Inf'))
if new_item not in lst:
     r.rpush(list_name, new_item)

答案 5 :(得分:1)

如果您不能使用SET(如果要实现某些阻止POP / PUSH列表的功能),则可以使用简单的脚本:

script load 'local exists = false; for idx=1, redis.call("LLEN",KEYS[1]) do if (redis.call("LINDEX", KEYS[1], idx) == ARGV[1]) then exists = true; break; end end; if (not exists) then redis.call("RPUSH", KEYS[1], ARGV[1]) end; return not exists or 0'

这将返回您添加的脚本的SHA代码。

然后致电:

evalsha 3e31bb17571f819bea95ca5eb5747a373c575ad9 1 test-list myval

其中

  • 3e31bb17571f819bea95ca5eb5747a373c575ad9(您添加的脚本的SHA代码)
  • 1 —是参数的数量(此功能为1不变)
  • test-list-您的列表名称
  • myval-您需要添加的值

如果添加了新项目,则返回1;如果已经在列表中,则返回0。

答案 6 :(得分:0)

在添加到任务工作者队列时遇到了此问题,因为我想避免添加许多重复的任务。使用Redis集(很多人都建议)会很好,但是Redis集没有像BRPOPLPUSH这样的“阻塞弹出”,因此它们不适用于任务队列。

因此,这是我略微不理想的解决方案(在Python中):

def pushOnlyNewItemsToList(redis, list_name, items):
    """ Adds only the items that aren't already in the list.
    Though if run simultaneously in multiple threads, there's still a tiny chance of adding duplicate items.
    O(n) on the size of the list."""
    existing_items = set(redis.lrange(list_name,0,-1))
    new_items = set(items).difference(existing_items)
    if new_items:
        redis.lpush(list_name, *new_items)

请注意文档字符串中的警告。

如果您需要真正保证没有重复,则可以选择在Re​​dis管道中运行LREM和LPUSH,如0xAffe的回答。这种方法会减少网络流量,但不利于重新排序列表。如果您不在乎列表顺序,这可能是最好的一般答案。