Вопрос довольно абстрактный:
Стоит задача реализации рейтинга и наград пользователей сайта. За определенные действия на сайте пользователь получает награду и определенное количество рейтинга. Приведу примеры наград:
Собственно вопрос: как грамотно реализовать такой функционал?
Вижу 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.
И достижения можно хранить в массиве и их условие, и не использовать для этих целей базу, из плюсов нет лишних запросов в БД, из минусов нет возможности быстро их менять.
Комментариев нет:
Отправить комментарий