Уникальное значение в списке/наборе redis

Я хочу создать список существующих продуктов в redis, но я хочу проверить, существует ли имя продукта уже (двойная проверка).

Мой список в настоящее время принимает дубликаты, поэтому: Может ли кто-нибудь помочь мне показать, как добавить уникальное значение в список?

Ответ 1

Вместо использования списка используйте набор. Установки - это контейнеры для уникальных объектов. Каждый объект может отображаться только один раз в наборе. Взгляните на команды, связанные с набором: http://redis.io/commands/#set.

И пример использования redis-cli (мы пытаемся добавить "Продукт один" дважды, но он появляется только один раз в списке продуктов):

$ redis-cli
127.0.0.1:6379> sadd products "Product One"
(integer) 1
127.0.0.1:6379> sadd products "Product Two"
(integer) 1
127.0.0.1:6379> sadd products "Product Three"
(integer) 1
127.0.0.1:6379> sadd products "Product One"
(integer) 0
127.0.0.1:6379> smembers products
1) "Product Three"
2) "Product One"
3) "Product Two"
127.0.0.1:6379>

Ответ 2

Это мое (безрассудное) решение, чтобы сохранить Redis List уникальным. (реализация в Ruby)

def push_item_to_the_list(LIST_KEY, item)
 insert_status = Redis.linsert(LIST_KEY, 'before', item, item)

 if insert_status == -1
   Redis.lpush(LIST_KEY, item)
 else
   Redis.lrem(LIST_KEY, 1, item)
 end
end

Каждый раз, когда вы хотите нажимать или вставлять элемент в свой список, проверьте, сможет ли команда LINSERT поместить этот элемент сразу после одного и того же элемента (это единственный способ узнать, является ли этот элемент уже в списке redis или нет).

Если LINSERT вернет статус -1, это означает, что он не смог найти элемент в вашем списке - все в порядке (вы можете нажать его или вставить сейчас).

Если LINSERT вернет другое значение (размер списка в другом случае) - это значит, что он смог найти элемент уже, и он смог вставить другой элемент сразу после предыдущего. Это означает, что у вас есть (как минимум) дублирование вашего элемента. Теперь вы можете удалить один из них.

Ответ 3

Почему бы просто не позвонить Redis.lrem раньше? Поэтому, если он обнаружит какие-либо вхождения предмета, удалит их, иначе ничего не будет делать. Примерно так:

def push_item_to_the_list(LIST_KEY, item)
   Redis.lrem(LIST_KEY, 0, item)
   Redis.lpush(LIST_KEY, item)
end

Ответ 4

Если вам нужно поддерживать порядок и уникальность, вы можете использовать отсортированный набор

127.0.0.1:6379> zadd products 1 "Product One"
(integer) 1
127.0.0.1:6379> zadd products 2 "Product Two"
(integer) 1
127.0.0.1:6379> zadd products 3 "Product Tree"
(integer) 1
127.0.0.1:6379> zadd products 4 "Product Four"
(integer) 1
127.0.0.1:6379> zrange products 0 -1
1) "Product One"
2) "Product Two"
3) "Product Tree"
4) "Product Four"

Ответ 5

Я предлагаю вариант, который создает уникальный список, элементы которого не теряют своей позиции. Эта опция работает намного быстрее, чем lpush, lrem, rpop. В то же время он поддерживает функционал sadd, spop.

Пример кода PHP:

public function addJobs(array $jobs): int
{
    foreach ($jobs as $key => $job) {
        $hash = hash('md4', $job);
        if (0 === $this->client->hsetnx('QUEUE-HASHES', $hash, 1)) {
            unset($jobs[$key]);
        }
    }

    return $this->client->rpush('QUEUE', $jobs);
}

public function popJobs(int $count): array
{
    if ($count < 1) {
        throw new \InvalidArgumentException('Jobs count must be greater than zero');
    }
    $index = $count - 1;
    $jobs = $this->client->lrange('QUEUE', 0, $index);
    if (\count($jobs)) {
        $this->client->ltrim('QUEUE', $count, -1);
        $hashes = [];
        foreach ($jobs as $job) {
            $hashes[] = hash('md4', $job);
        }
        $this->client->hdel('QUEUE-HASHES', $hashes);
    }

    return $jobs;
}