10

By using phpredis, I have saved some data in pagination like this:

   review/itemA/1
   review/itemA/2 

where 1 and 2 are page numbers. I read in the document that you can use wildcards to retrieve multiple keys.

$allKeys = $redis->keys('*');   // all keys will match this.
$keyWithUserPrefix = $redis->keys('user*');

But can I delete all the old keys using wildcards as well when someone has posted a new review? Can I do something like:

$redis->delete('review/itemA/*'); // or  $redis->delete('review/itemA*')

It didn't work however.

Ramratan Gupta
  • 1,056
  • 3
  • 17
  • 39
RedGiant
  • 4,444
  • 11
  • 59
  • 146
  • Never use keys command on production environment as it will block the whole DB until the searched key is found. Instead you can use Scan to search specific key for production env. – Akash Gangrade Sep 13 '18 at 09:16

8 Answers8

4

No - Redis' DELlete does not accept wildcards, you have to name the keys explicitly. See here for possible directions: https://stackoverflow.com/a/23399125/3160475

Community
  • 1
  • 1
Itamar Haber
  • 47,336
  • 7
  • 91
  • 117
  • 1
    Thanks. I ended up using `$allKeys = $redis->keys('itemA*');` and looped over the results to delete them one by one. Not sure if that is the best way of doing it. – RedGiant Aug 30 '15 at 12:12
  • 2
    Definitely one of the worst ways ;) `KEYS` is an evil command that you should, as a rule, refrain from using (unless thou be brave, fool or both) – Itamar Haber Aug 30 '15 at 14:13
4

When using phpredis, you can get the prefix (which phpredis automatically prepends everywhere) and delete a pattern of keys that way :

<?php
...

$prefix = $redisClient->getOption(Redis::OPT_PREFIX);
$redisClient->delete(array_map(
    function ($key) use ($prefix) {
        return str_replace($prefix, '', $key);
    }, $redisClient->keys('*'))
);
KevinS
  • 8,087
  • 2
  • 17
  • 9
  • A little improvement to ensure removing the string (prefix) starting to the left: `preg_replace( "/^${prefix}/", '', $key );` in favor of `str_replace`. – David DIVERRES Apr 07 '21 at 21:13
2

With Predis, I do it like this:

    public function delete($key) {
        $keys = $this->client->keys($key);
        foreach ($keys as $key) {
            $this->client->del($key);
        }
    }
raoulsson
  • 14,978
  • 11
  • 44
  • 68
2

Predis (->del) allows to pass a keys array too.
It works here and is faster than the del inside the foreach.

$prefix = $this->client->getOptions($this->OPT_PREFIX);
$keys = $this->client->keys("$key*");
if ($keys) $this->client->del($keys);
AymDev
  • 6,626
  • 4
  • 29
  • 52
1
$bash = 'redis-cli --scan --pattern "' . $path . '*" | xargs -L 1000 redis-cli DEL';

$res = @shell_exec($bash);
tomek
  • 27
  • 2
  • 2
    Please refrain from posting code-only answers as they do not help the community to improve by learning how to solve a problem. Try to explain why your solution would help with the problem with the code instead. – Nahuel Ianni Dec 16 '16 at 12:28
  • 2
    It's better to add more context/explanation around code (as opposed to just having a code-only answer) as that makes the answer more useful. – EJoshuaS - Stand with Ukraine Dec 16 '16 at 17:07
  • 1
    While this code snippet may solve the problem, it doesn't explain why or how it answers the question. Please [include an explanation for your code](//meta.stackexchange.com/q/114762/269535), as that really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. **Flaggers / reviewers:** [For code-only answers such as this one, downvote, don't delete!](//meta.stackoverflow.com/a/260413/2747593) – Scott Weldon Dec 17 '16 at 00:04
1

I just use

$redis->delete($redis->keys('*'));

It's works fine for me.

Akuma
  • 561
  • 1
  • 4
  • 16
0

There is no wildcard for delete function. workaround as follows,

// returns total number of keys deleted
function delete($key) {
    if (empty($key)) {  // empty key can delete all
      return false;
    }
    $keys = $redis->keys("$key*");  // keys() function returns array of key strings. `*` wild card pattern can be changed as per need
    if(!$keys) {
        return 0;
    }
    $prefix = $redis->getOption(\Redis::OPT_PREFIX); // keys already have prefix, so we clear until delete finish.
    $redis->setOption(\Redis::OPT_PREFIX, '');
    $count = $redis->del($keys);  // del() function delete array of keys and returns number of keys deleted.
    $redis->setOption(\Redis::OPT_PREFIX, $prefix);

    return $count;
}

Note: As @Akash Gangrade commented, keys() not advised to use due to performance. you can consider Tags based cache invalidation like https://symfony.com/doc/current/components/cache/cache_invalidation.html#tag-aware-adapters

Bala
  • 913
  • 9
  • 18
0

Using scan and unlink is best practise as they are non blocking commands unlike keys and delete

# The keys set in redis
/*
1) "review/itemA/5"
2) "review/itemA/2"
3) "review/itemA/3"
4) "review/itemA/1"
5) "review/itemA/4"
*/

/**
 * vars used for scan
 */
$i = null;
$result = [];

/**
 * scan redis using desired pattern
 */
while ($result != 0) {
    $result = $redis->scan($i, 'review/itemA/*');
    if (!empty($result)) {
        $all_keys[] = $result;
    }
}

# Use call_user_func_array to flatten multidimensional array into indexed array
## Scan may return duplicate keys, so use array_unique
$unlink_keys = array_unique(call_user_func_array('array_merge', $all_keys));

# As of Redis 4.0 use unlink instead of del to stop blocking
$redis->unlink($unlink_keys);
Bam
  • 133
  • 1
  • 8
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 25 '22 at 05:48