【问题标题】:select many through many... kind of从许多中选择许多...种
【发布时间】:2025-12-20 23:55:12
【问题描述】:

这是我在 Stack 上的第一篇文章,如果我违反任何协议,请多多包涵。

我正在使用 Rails (2.1.2) 开发一个项目,我的关系场景如下所示:

event [has_many] days

人们(不同类别的)可以报名参加活动日,并给出以下绑定结果:

category [has_many] customers [has_many] orders [has_many] days  
[belongs_to] event

现在,我想获得一位客户或某个类别中所有客户的“事件”总数,但我遇到了困难。 AFAIK,没有办法通过对象数组执行简单的“查找”,对吗?那么,解决方案是什么?嵌套循环,以及从订单中的“天”中获取“事件”的收集方法?

如果我不清楚,请告诉我。

感谢您的帮助!

【问题讨论】:

  • 您的第一篇文章实际上是与编程相关的,所以您走在正确的轨道上。

标签: ruby-on-rails find associations


【解决方案1】:

我个人会使用 MySQL 语句来执行此操作。我不确定,但我认为它比其他示例快得多(使用 rails 提供的关联方法)。

这意味着在客户模型中,您可以执行以下操作: (请注意,我假设您使用的是默认关联键:'model_name_id')

class Customer
  def events
    Event.find_by_sql("SELECT DISTINCT e.* FROM events e, days d, orders o, customers c WHERE c.id=o.customer_id AND o.id=d.order_id AND e.id=d.event_id")
  end
end

这将返回与用户关联的所有事件,并且没有重复('DISTINCT' 关键字确保了这一点)。与上面的示例一样,您将丢失有关用户注册日期的确切信息。如果您需要该信息,请说出来。

另外,我没有为您的 Category 模型提供示例,因为我认为您可以自己调整我的示例。如果没有,请告诉我。

编辑:

我刚刚读到你只是想计算事件。使用 count 语句可以更快(或至少减少内存占用)。要使用它,只需使用以下函数:

def event_count
  Event.count_by_sql(SELECT DISTINCT COUNT(e.*) FROM ... ... ...
end

【讨论】:

    【解决方案2】:

    您的模型可能如下所示:

    class Category
      has_many :customers
    
    class Customer
      has_many :orders
      has_many :days, :through => :orders # I added this
      belongs_to :category
    
    class Order
      has_many :days
      belongs_to :customer
    
    class Day
      belongs_to :event
      belongs_to :order
    
    class Event
      has_many :days
    

    这样您就可以为客户计算事件数:

    events = customer.days.count(:group => 'event_id')
    

    它会像这样返回 OrderedHash:

    #<OrderedHash {1=>5, 2=>13, 3=>0}>
    

    您可以通过以下方式获取事件计数:

    events[event_id]
    
    events[1] # => 5
    events[2] # => 13
    etc.
    

    如果你想要 uniq 事件的总数:

    events.size # => 3
    

    如果要计算类别中所有客户的事件,我会这样做:

    events = {}
    category.customers.each {|c| events.merge!(c.days.count(:group => 'event_id') ) }
    events.size # => 9 - it should be total number of events
    

    但在这种情况下,您会丢失每个事件出现次数的信息。

    我没有测试这个,所以可能会有一些错误。

    【讨论】: