Положение в рейтинге
У меня есть приложение 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;