Страницы

Поиск по вопросам

суббота, 6 июля 2019 г.

Реализация наград и рейтинга пользователей

Вопрос довольно абстрактный:
Стоит задача реализации рейтинга и наград пользователей сайта. За определенные действия на сайте пользователь получает награду и определенное количество рейтинга. Приведу примеры наград:

Собственно вопрос: как грамотно реализовать такой функционал?
Вижу 2 способа:
при определенных действиях пользователя определять, выполнены ли условия для получения той или иной награды, запоминать в базе, что этот пользователь получил награду, а рейтинг пересчитывать исходя из того, какие награды он получил (будет таблица rewards с полями id, name, icon, rating), просто складывать значения поля rating для каждого пользователя в таблице users хранить текущее значение рейтинга и наращивать это поле по мере получения новых наград
И вижу здесь одну проблему:
допустим пользователь получил награду, например, за 100-й лайк к своей записи (в БД создалась запись о том что данный пользователь имеет эту награду), потом один из тех кто поставил лайк убирает его, и уже становится не 100, а 99 лайков. Как отслеживать подобные ситуации?
И, опять же, по примеру выше, в какой момент лучше проверять выполнение условий этой награды? Можно такие проверки делать каждый раз, когда кто-то ставит лайк (делать запрос в БД и проверять, нет ли в списке его записей такой, которую лайкнули не менее 100 раз. Но может есть другие, более правильные, варианты?
Буду рад любому совету или замечанию по данному вопросу, заранее благодарю! ;)


Ответ

Предлагаю такую структуру данных:
Для метрик:
Создать таблицу с метриками:
+----------+----------+-----+----------+ | users_id | metric_x | ... | metric_y | +----------+----------+-----+----------+ | 1 | 10 | ... | 310 | | 2 | 34 | ... | 103 | +----------+----------+-----+----------+
Либо в более нормализованном виде (но за 1 запрос будет уже не строка, а список):
+----------+------------+----------+ | users_id | name | value | +----------+------------+----------+ | 1 | 1 | 10 | | 1 | 2 | 310 | | 2 | 1 | 34 | | 2 | 2 | 103 | +----------+------------+----------+
Для достижений:
Ссылка на пользователя и на достижение (можно в список достижений уже поместить фото, описание, и если достижений не много можно хранить их в массиве)
+----------+-----------------+ | users_id | achievement_id | +----------+-----------------+ | 1 | 1 | | 1 | 2 | | 2 | 1 | | 3 | 8 | +----------+-----------------+
Таблица с достижениями (многоточие означают информацию о достижении):
и поле metric_id говорят какая метрика и value и когда достижение будет выполнено, но у этого примера есть ограничения его скорей всего будет сложно использовать например для достижений по 2 метрикам или достижениям который зависят от достижений и скорей всего стоит отказать от достижений или объединить их с метриками.
+----+-----+------------+-------+ | id | ... | metric_id | value | +----+-----+------------+-------+ | 1 | ... | 1 | 300 | | 2 | ... | 2 | 200 | | 3 | ... | 1 | 50 | +----+-----+------------+-------+
И тригеры которые будут вызываться при нужных действиях:
И пример псевдокода (использую нормализованную таблицу для метрик):
public function trigger_update($user_id, $metric_id, $metric_value, $achievement) { $sql = "UPDATE metric SET value = value + {$metric_value} WHERE users_id = {$user_id} AND name = {$metric_id}";
// выполнения запроса и получения элемента $metic_value = sql_query($sql).commit();
$sql = "SELECT * FROM achievement WHERE id = {$achievement} AND metric_id = {$metric_id} AND value >= ${value}"; if (sql_query($sql).commit() !== Null){
$sql = "INSERT INTO users_achievement (users_id, achievement_id) VALUES ({$user_id}, {$achievement});"
// и да, нужен индекс что-бы записи были уникальны // и тут нужны обработка исключений или select что-бы нормально реагировать на то что у человека уже есть данное достижение. sql_query($sql).commit(); push_user($user_id, $metric_value); // и метод уведомления } }
p.s.
И достижения можно хранить в массиве и их условие, и не использовать для этих целей базу, из плюсов нет лишних запросов в БД, из минусов нет возможности быстро их менять.

Комментариев нет:

Отправить комментарий