Удаление нескольких ключей в redis-rb

Используя redis-rb в приложении Rails, следующее не работает:

irb> keys = $redis.keys("autocomplete*")
=> ["autocomplete_foo", "autocomplete_bar", "autocomplete_bat"]
irb> $redis.del(keys)
=> 0

Это отлично работает:

irb> $redis.del("autocomplete_foo", "autocomplete_bar")
=> 2

Я пропустил что-то очевидное? Источник:

# Delete a key.
def del(*keys)
  synchronize do
    @client.call [:del, *keys]
  end
end

который выглядит так, как будто он должен работать, чтобы передать массив...?

Ответы

Ответ 1

Небольшое кодирование того, как работает оператор splat:

def foo(*keys)
  puts keys.inspect
end

>> foo("hi", "there")
["hi", "there"]

>> foo(["hi", "there"])
[["hi", "there"]]

>> foo(*["hi", "there"])
["hi", "there"]

Таким образом, передача в регулярном массиве приведет к тому, что этот массив будет оцениваться как один элемент, так что вы получите массив внутри массива внутри вашего метода. Если вы предируете массив с * при вызове метода:

$redis.del(*keys)

Это позволяет методу знать, чтобы распаковать его/не принимать никаких дополнительных аргументов. Таким образом, это должно решить проблему, которая у вас есть!

Только для дальнейших разъяснений это работает:

>> foo("hello", *["hi", "there"])

Это вызывает синтаксическую ошибку:

>> foo("hello", *["hi", "there"], "world")

Ответ 2

Для приложения Rails, над которым я работаю, мне нужно было проверить результаты загрузки и выгрузки данных redis.

Пространство имен определяется средой, избегает взаимодействия с разработкой. Это хорошо работает.

def clear_redis_cache
  keys = $redis.keys "#{namespace}*"
  $redis.del(*keys) unless keys.empty?
end

Ответ 3

Это лучше достигается с помощью перечислителя, возвращаемого scan_each.

scan_each(match: 'autocomplete_*').each do |key|
  del key
end

Это не загружает все соответствующие ключи в память одновременно, поэтому оно не будет связано с памятью.