清空 Redis 列表中的所有条目

97

假设您在Redis中有一个LIST数据类型。 如何删除其中的所有条目? 我已经尝试过这个:

LTRIM key 0 0
LTRIM key -1 0

这两种方法都会保留第一个元素。如果想要删除所有元素,可以使用以下代码:

LTRIM key 0 -1

我没有看到单独清空一个列表的命令。


2
@DavidJames:把它看作另一种拼写“foo”的方式。我遵循Redis自己文档中使用的约定:http://redis.io/commands/ - Paul A Jungwirth
是的,在Redis中,所有数据结构都是键。这并不意味着在示例中使用“键”很有用。相反,我认为使用mylist会使您的问题更清晰。例如,http://redis.io/commands/ltrim/ 写道:LTRIM mylist 1 -1。您引用的页面是一个命令参考,不应被视为制作良好示例的“惯例”。 - David J.
7个回答

175

删除这个键,就会清除所有的项。没有这个列表就像没有任何项一样。当你尝试访问不存在的键时,Redis不会抛出任何异常。

DEL key

这里是一些控制台日志。

redis> KEYS *
(空列表或集合)
redis> LPUSH names John
(整数) 1
redis> LPUSH names Mary
(整数) 2
redis> LPUSH names Alice
(整数) 3
redis> LLEN names
(整数) 3
redis> LRANGE names 0 2
1) "Alice"
2) "Mary"
3) "John"
redis> DEL names
(整数) 1
redis> LLEN names
(整数) 0
redis> LRANGE names 0 2
(空列表或集合)

有没有一种方式可以将“LRANGE names 0 2”和“DEL names”两个操作合并为一个原子操作? - refaelos
1
有一件事,使用Del可能会产生额外的开销。时间复杂度:O(N),其中N是要删除的键数。当要删除的键保存的值不是字符串时,该键的单个复杂度为O(M),其中M是列表、集合、排序集或哈希中元素的数量。删除一个保存字符串值的单个键的时间复杂度为O(1)。文档 - ChewOnThis_Trident
3
这种方法很危险,因为它还会删除键的 TTL。 - Saitama

22

更新 2021年06月11日

有不同的方法可以从List中删除所有元素:

步骤1: 使用一般DEL命令从Redis中删除任何键,例如Anurag的解决方案

DEL list

步骤2: 使用LTRIM命令并应用文档中的下一个条件。

如果start大于列表的end,或者start > end,则结果将是一个空列表(这将导致键被删除)。

因此,任何以下命令都将起作用,或者使用Mohd Abdul Mujib的解决方案

LTRIM list 999 0

LTRIM list 1 0

LTRIM list 4 1

但是,需要注意不要使用负数作为起始索引,因为文档中提到:

起始和结束也可以是负数,表示从列表末尾的偏移量开始计算,其中-1表示列表的最后一个元素,-2表示倒数第二个元素,依此类推。

如果列表包含多个元素,则下一个命令将删除列表下的所有元素。但是,如果列表只包含一个元素,则不会删除任何内容。

LTRIM list -1 0

解释

第一种情况(列表包含多个元素)-1作为起始索引将转换为最后一个具有索引4的元素(如果列表包含4个元素)。因此,应用了条件start > end

第二种情况(列表仅包含一个元素)-1作为起始索引将转换为具有索引0的最后一个元素。因此,条件变为start == end而不是start > end

以下是上述命令的示例:

redis 127.0.0.1:6379> RPUSH mylist four 1 3 1
(integer) 4
redis 127.0.0.1:6379> KEYS *
1) "test4"
2) "firstList"
3) "mylist"
redis 127.0.0.1:6379> LTRIM mylist 999 0
OK
redis 127.0.0.1:6379> KEYS *
1) "test4"
2) "firstList"
redis 127.0.0.1:6379> RPUSH mylist four 1 3 1
(integer) 4
redis 127.0.0.1:6379> KEYS *
1) "test4"
2) "firstList"
3) "mylist"
redis 127.0.0.1:6379> LTRIM mylist -1 0
OK
redis 127.0.0.1:6379> LRANGE mylist 0 -1
(empty list or set)
redis 127.0.0.1:6379> KEYS *
1) "test4"
2) "firstList"
redis 127.0.0.1:6379> RPUSH mylist four
(integer) 1
redis 127.0.0.1:6379> KEYS *
1) "test4"
2) "firstList"
3) "mylist"
redis 127.0.0.1:6379> LTRIM mylist -1 0
OK
redis 127.0.0.1:6379> KEYS *
1) "test4"
2) "firstList"
3) "mylist"

正如已被接受的答案评论中提到的那样:DEL键也会删除列表的ttl。 - patrick
请在您的回答中更正错误的说法;删除只有一个值的列表是可能的:https://dev59.com/BWkw5IYBdhLWcg3wirCs#51497664 - EliadL
@EliadL 我更新了我的答案,以澄清我的建议解决方案仍然是正确的(在测试后),提供另一种正确的解决方案,而且他的解决方案将适用于所有情况[列表中有一个元素或多个元素]。 - ahmed hamdy
@ahmedhamdy请注意,你回答中的开头句仍然是一个错误的声明。 - EliadL
@EliadL 我编辑了我的答案,使其更加清晰,因为之前的答案中包含了虚假的声明,即在某些情况下,具有相同起始和结束索引的确切命令(在开头句子中)未能删除所有元素,如我所提到的,请尝试一下以找出正确的答案,最后感谢您的评论。 - ahmed hamdy

6

只需使用LTRIM命令即可。... 这里的魔法是使用startend大。

LTRIM key 99 0

突然间,所有元素都消失了,就像 * poof * 一样,就在你眼前!没有任何残留物,也没有任何疑问。

注意:这将导致键被“删除”(即被删除),如此处所述。

...如果 start 大于列表的末尾或 start > end,则结果将是一个空列表(这会导致键被删除)。


你为什么更喜欢这个而不是像@Anurag的答案中使用DEL键?它们似乎有相同的效果。 - Paul A Jungwirth
坦白说,我没有时间去查看基准测试,当我发现上述方法时,我只是在阅读文档,想着可能也可以提一下。 - Mohd Abdul Mujib
1
好的,谢谢!我点赞是因为我可以想象出使用LTRIM重复地运行算法,并且了解第二个参数低于第一个参数时会发生什么。我可以看到如何利用这种行为可以使一些代码更加优雅。 - Paul A Jungwirth

0

似乎没有原子操作可以做到这一点。我发现的(示例是使用StackExchange.Redis的C#)是:

cacheDb.ListTrim(key, 0, 0); // remove all elements but the first one
cacheDb.ListLeftPop(key);    // then remove the first one

将以两个步骤删除所有元素(其中cacheDb是您连接的类型为IDatabase的数据库,而keyRedisKey类型)。

我认为在cli语法中,这将是:

LTRIM key 0 0
LPOP key

然而,它似乎执行的是与 cacheDb.KeyDelete(key) 相同的操作(或者在cli语法中为 DEL key)- 因为在这两种情况下,键都不再被找到。


0

这可能是一个迟到的回复,但我还是放在这里,以防有人仍然需要那个功能。

简短的答案

ltrim mylist 0 - (n + 1),其中mylist是关键字,n是mylist的长度。

长的答案

ltrim的工作方式是取两个索引并返回它们之间(包括索引)的元素。

Ltrim list startIndex endIndex

例如,假设我们有一个redis列表,其关键字为mylist,其中包含10个条目:

ltrim mylist 0 5会将列表修剪为从索引0开始到索引5结束的元素。丢弃那些超出该范围的元素。

幸运的是,redis列表操作支持负索引,在某些情况下非常有用。通常是当您不知道列表的长度时。

-1指最后一个元素,-2表示倒数第二个元素,以此类推。(-n)是第一个元素。

超出范围的索引并不会对其造成伤害。如果结束索引大于列表长度,则redis将其视为等于最后一个索引。

这就是为什么ltrim mylist 0,-(n +1)会清空列表。因为(-n)等同于索引0。将其加1后,该范围内没有任何元素,因为它在第一个元素之前。


感谢您分享您的见解。作为对您答案的扩展,您可以简单地提供一个足够大于列表的N值,以确保删除所有项目。例如 ltrim mylist 0 -99999 - Dave Johnson

0

我尝试了这个方法,对我很有效。只需要将其中的myList替换成你的列表名称并执行如下代码即可:

redis-cli KEYS “你的列表名称:*" | xargs redis-cli DEL

1
虽然这个方法可以运行,但 keys 是一个非常耗费资源的操作,需要解析数据库中的每一个键,而在这种情况下是完全不必要的,或者说在大多数情况下都是如此。 - Adalcar

-1

被接受的答案是错误的。假设我有

redis 127.0.0.1:6379> KEYS * 
1) "newKey" 
2) "firstHash" 
3) "secondList" 
4) "test4" 
5) "firstList" 
6) "mylist" 

使用Ahmed的示例,这实际上是正确的。 现在,如果我执行:

DEL 'test4'

我最终得到:

1) "newKey" 
2) "firstHash" 
3) "secondList" 
4) "firstList" 
5) "mylist"` 

所以,我并没有从'test4'列表中删除所有条目,我 删除了 test4 本身。这不是一回事。我的一个小应用程序中,列表键是从几个数据计算出的哈希值(嗯,它们都是这样吗?),有时这些列表会被清除,但是空列表和不存在的列表的语义非常不同。所以,不,我不想DEL 'myhashes',我只想删除所有条目。

当心,哦,你们在这里徘徊的人。


如果您查看下面引用的页面,您会发现实际上语义是相同的!从以下网址中获取:LPUSH命令在头部插入新元素,而RPUSH在尾部插入新元素。当其中一个操作针对空键执行时,将创建一个新列表。同样,如果列表操作将清空列表,则从键空间中删除该键。这些语义非常方便,因为所有列表命令在使用不存在的键作为参数调用时,将完全像使用空列表一样运行。 - Dominic
从权威渠道得到的消息:如果列表操作将使列表为空,则同样会从键空间中删除该键。那么,{ [], [], [] } === { [] } 吗?对我来说不是这样。我猜我们处于不同的拓扑空间.... :) - deimosaffair
最初的问题是如何在Redis中删除整个列表。因此,如果您删除键或删除所有条目并使Redis自动删除键,则会得到相同的结果。所以我不确定您在 { [], [], [] } === { [] } 中的意思是什么。 - Dominic
从列表中删除最后一个元素等同于删除该键。这个链接对于LIST也是一样的(使用RPOPLPUSH进行测试) https://www.bennadel.com/blog/2965-redis-doesn-t-store-empty-sets-or-hashes-and-will-delete-empty-sets-and-hashes.htm - Kanagavelu Sugumar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接