Положение в рейтинге
У меня есть приложение Rails со следующими моделями:
- пользователь
- ставка
Пользователь имеет many_bets и ставки принадлежат Пользователю. Каждая ставка имеет значение Profitloss, которое указывает, сколько пользователь выиграл/проиграл на этой ставке.
Итак, чтобы вычислить, сколько конкретный пользователь выиграл в целом, я циклически перебираю его ставки следующим образом:
User.bets.sum(:profitloss)
Я хотел бы показать пользователю его рейтинг по сравнению со всеми другими пользователями, который может выглядеть примерно так это:
"ваш общий рейтинг: 37-е место"
Для этого мне нужно суммировать общий выигрыш на одного пользователя и выяснить, в каком положении находится текущий пользователь.Как это сделать и как это сделать, чтобы не перегружать сервер:)
Спасибо!
3 ответа:
Вы можете попробовать что-то похожее на
User.join(:bets). select("users.id, sum(bets.profitloss) as accumulated"). group("users.id"). order("accumulated DESC")И затем найдите в полученном списке "пользователей" (не реальных пользователей, у них есть только два значимых атрибута, их ID и атрибут
accumulatedс суммой), соответствующий текущему.В любом случае, чтобы получить позицию одного пользователя, вы должны вычислить позицию всех пользователей
accumulated, но, по крайней мере, это только один запрос. Еще лучше, вы можете хранить в пользовательской модели накопленное значение и запрашивать только его для ранжирования.
Если у вас большое количество пользователей и ставок, вы не сможете вычислить и отсортировать глобальный профитлосс каждого пользователя "по требованию", поэтому я предлагаю вам использовать задачу рейка, которую вы регулярно планируете (один раз в день, каждый час и т. д...)
Добавьте столбец
positionв модельUser, получите список всех пользователей, вычислите их глобальный profitloss, отсортируйте список пользователей с их profitloss и, наконец, обновите атрибутpositionкаждогоUserс их позицией в списке.
Лучший способ сделать это-сохранить предварительно вычисленный итог в вашей базе данных либо на самой модели
user, либо на отдельной модели, которая имеет отношение 1:1 кuser. Если вы этого не сделаете, вам придется вычислить сумму для всех пользователей в любое время, чтобы получить их рейтинг, что означает полную работу таблицы с таблицейbets. Тем не менее, этот запрос даст вам желаемые результаты, если более чем 1 человек имеет тот же итог, он будет засчитан как рейтинг X:select id, (select count(h.id) from users u inner join (select user_id, sum(profitloss) as `total` from bets group by user_id) b2 on b2.user_id = u.id, (select id from users) h inner join (select user_id, sum(profitloss) as `total` from bets group by user_id) b on b.user_id = h.id where u.id = 1 and (b.total > b2.total)) as `rating` from users where id = 1;Вам нужно будет подключить
user.idк запрос вwhere id = XЕсли вы добавляете столбец в таблицу
user, чтобы отслеживать их общее количество, запрос немного проще, в этом примере имя столбцаtotal_profit_loss:select id, total_profit_loss, (select count(h.username)+1 from users u, (select username, score from users) h where id = 1 and (h.total_profit_loss > u.total_profit_loss)) as `rating` from users where id = 1;