Как хранить данные в Redis без дублирования, при условии что они не полностью уникальные

прошу совета по хранению данных в Redis. Задача следующая, есть пользователи и есть их история просмотра видео контента, например так выглядит одна запись истории:

{"user_id": 1,"content_id": 123, "viewed_at": 123123}

Этих записей очень много и раньше они хранились в Postgres, но это стало сильно нагибать базу. Приняли решение временно вынести её в Redis.

Сейчас я пытаюсь хранить их в Redis List, каждый лист это история просмотра одного пользователя, есть ограничение по количеству записей на пользователя например 100.

При этом мне не нужно хранить исторические записи по просмотру одного контента, только последнюю.

Redis Set мне не помогает, потому что в записях есть изменяющиеся поля "viewed_at" например. Пока пришла идея которая работает, но мне не нравится, это выгружать список пользователя целиком, проверять на наличие в нём дублей по полю "content_id", убирать их и вставлять лист заново.

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

upd

Пока только такая реализация удовлетворяет требованиям по хранению. Плюсы:

  1. Контроль занимаемого места (длина каждого листа)
  2. Пагинация по истории
  3. Сортировка

Минусы: Операция lrem дорогая O(N+M) N - количество записей в листе, M - количество удаляемых элементов.

all_histories = await self.redis.lrange(redis_list_name, 0, -1)

for i, v in enumerate(all_histories):
    if (
        v["object_id"] == latest_history["object_id"]
        and v["content_id"] == latest_history["content_id"]
    ):
        await self.redis.lrem(redis_list_name, 1, all_histories [i])

await self.redis.lpush(redis_list_name, history)
await self.redis.ltrim(redis_list_name, 0, MAX_LEN)

Ответы (1 шт):

Автор решения: Alexander Petrov

По-моему, в данном случае лучше использовать тип данных HASH.

Заносим данные пользователя:

hset user:1 content:123 123123

Заносим ещё один просмотр другого контента в то же время:

hset user:1 content:456 123123

Меняем время просмотра одного контента:

hset user:1 content:123 010124

Смотрим данные:

hgetall user:1
1) "content:123"
2) "010124"
3) "content:456"
4) "123123"
→ Ссылка