如何根据关联计数的子样本订购记录?

时间:2013-05-25 11:02:49

标签: ruby-on-rails

在Rails 3.2中说我有3个模特:运动员,赛事和国家

Class Athlete
  has_many :events
  has_many :countries, through: :event
end

Class Event
  belongs_to :athlete, counter_cache: true
  belongs_to :country, counter_cache: true
end

Class Country
  has_many :events
  has_many :Athletes, through: :event
end

所以我现在可以根据他们参加的活动数量轻松生成一系列运动员。

scope :ranked, :order => 'athletes.events_count DESC' 

但是,如果我需要在特定国家/地区进行了一系列比赛的运动员,并按照在该国家/地区举办的活动数量排序,该怎么办?

#country
def show
  @country.find(params[:id])
  @athletes_leaderboard = Athlete.includes(:events).where(id: @country.events.uniq.map(&:athlete_id)).ranked
end

为我提供了一个在该国家/地区进行了比赛的运动员的唯一列表,但是按照事件计数排名,而不是按国家/地区的事件计数进行排名。

如何在保持数据库性能的同时按国家/地区事件计数进行排序。

1 个答案:

答案 0 :(得分:0)

查询涉及与子查询的一些连接。

country_id = params[:id]
subsql = Event.select("events.athlete_id AS a_id, count(events.id) AS country_event_count").where("events.country_id = ?", country_id).group("a_id").to_sql
@athletes_leaderboard = Athlete.joins("JOIN (#{subsql}) AS participated_events ON participated_events.a_id = athletes.id").
  order("participated_events.country_event_count DESC")

@athletes_leaderboard的结果不再是ActiveRecord::Relation。它是数据库结果行。您需要遍历结果并在视图中呈现它。例如(使用HAML):

- @athletes_leaderboard.each do |athlete_data|
  = link_to athlete_data["name"], athlete_path(athlete_data["id"])

您可能希望将排行榜缓存在内存存储区(如Memcache)中,以便数据库不会经常受到攻击。