Rails:通过关联聚合查询

时间:2015-02-28 08:33:59

标签: ruby-on-rails ruby ruby-on-rails-4 rails-activerecord

在rails中,是否存在通过has_many :through关联进行聚合查询的ActiveRecord方式?

编辑:我正在寻找一个数据库驱动的解决方案,而不是一堆Ruby迭代/修改。

编辑#2:我搞砸了。 Venue模型也是多对多的Show。

例如。想象一下(做作)这样的事情:

# Venue<->Show is many-to-many.
# Show<->Performer is many-to-many.

class Venue < ActiveRecord::Base
  has_many :bookings
  has_many :shows, through: :bookings
end

# Note "show" here would be "The Lion King," not a specific
# performance on a specific date.
class Show < ActiveRecord::Base
  has_many :bookings
  has_many :venues, through: :bookings

  has_many :engagements
  has_many :performers, through: :engagements
end

class Performer < ActiveRecord::Base
  has_many :engagements
  has_many :shows, through: :engagements
end

# Just a simple join model.
class Engagement < ActiveRecord::Base
  belongs_to :show
  belongs_to :performer
end

# Also a join model.
class Booking < ActiveRecord::Base
  belongs_to :venue
  belongs_to :show
end

如何在Venue上执行查询,该查询返回曾在那里执行的所有Performer的唯一集合?

谢谢!

2 个答案:

答案 0 :(得分:2)

由于您最终需要一组表演者,请从该模型开始。我们知道我们正在寻找一个特定的场地,所以让我们看看我们可以用来达到那个协会。

# Performer
has_many :shows, through: :engagements

# Show
has_many :venues, through: :bookings

宾果!我们可以从表演者到表演场地(Rails将自动找出从参与到节目和预订到场地的连接)。

ActiveRecord支持使用关联名称加入关联(注意:这仅适用于INNER联接):http://guides.rubyonrails.org/active_record_querying.html#using-array-hash-of-named-associations

在阅读该查询指南后,我们知道可以使用Hash语法加入嵌套关联。这让我们

Performer.joins(shows: :venues)

但是我们不能止步于此,因为我们将让所有表演者至少在一个场地至少参加过一次表演(在多场表演,参与,预订或场地中重复任何表演者 - 我们'我会暂时处理这些事情)。为了缩小集合范围,我们必须添加一个WHERE子句。链接指南的第12.3节解释了我们可以向连接表添加哈希条件。 缩小场地看起来像

venue = Venue.find(params[:venue_id])
Performer.joins(shows: :venues).where(venues: {id: venue.id})

现在我们所有表演者都在本场所有演出中演出!但是等等,如果他们玩过多个Show(或Engagement),我们仍然会有重复的表演者。为了删除重复项,我们使用uniq

把它们放在一起给了我们

venue = Venue.find(params[:venue_id])
Performer.joins(shows: :venues).where(venues: {id: venue.id}).uniq

答案 1 :(得分:0)

我认为你可以这样做:

venue = Venue.find(?)

# Select only unique Performer ids
unique_performer_ids = Performer.joins(:engagements).where(show_id: venue.show_id).distinct(:id)

# Select unique Performer objects
performers = Performer.where(id: unique_performer_ids)

可以将这两个查询合并为一个使用子查询。