【问题标题】:Order by association status count in Rails在 Rails 中按关联状态计数排序
【发布时间】:2020-11-10 14:35:45
【问题描述】:

我创建了一个与 Response 模型有 has_many 关联的候选模型

在响应模型中,我们还将状态存储为待处理和已完成

我想添加根据数量待定状态对候选人进行排序的范围

例如

Candidates1  -> repsones1 --> {status: "pending"}
             -> repsones2 --> {status: "completed"}
*******************************************************
Candidates2  -> repsones1 --> {status: "pending"}
             -> repsones2 --> {status: "pending"}
*******************************************************
Candidates3  -> repsones1 --> {status: "completed"}
             -> repsones2 --> {status: "completed"}
*******************************************************
Candidates4  -> repsones1 --> {status: "pending"}
             -> repsones2 --> {status: "pending"}

所以上面的例子,我想这样订购

Candidates2 #pending status count is 2
Candidates4 #pending status count is 2
Candidates1 #pending status count is 1
Candidates3 #pending status count is 0

我使用 Postgres 作为数据库

我不想在候选模型上添加任何计数属性

我尝试了一些范围

class Candidate < ActiveRecord::Base
  has_many :responses

  scope :order_by_pending_responses, -> {
     joins(:responses)\
    .order("responses.status='pending' DESC")
  }
end 

但得到重复的候选人 如果我在作用域上添加了 uniq 关键字,那么分页就会出错

【问题讨论】:

    标签: sql ruby-on-rails ruby psql


    【解决方案1】:

    SQL 中的ORDER BY 子句可以包含聚合和条件:

    scope :order_by_pending_responses, -> {
        left_joins(:responses)
          .group("candidates.id")
          .order("SUM(CASE WHEN responses.status = 'pending' THEN 1 ELSE 0 END) DESC")
    }
    

    【讨论】:

    • 非常感谢,但我使用 sum 而不是 count 并得到正确的结果。 order("sum(CASE WHEN response.status = 'pending' THEN 1 ELSE 0 END) DESC")
    • @Akshay 当然,你是对的。我修正了我的答案。
    【解决方案2】:

    试试这个:

    scope :order_by_pending_responses, -> {
        left_joins(:responses)
          .where(responses: { status: :pending })
          .group("candidates.id")
          .order("count(responses.id) DESC")
    }
    

    但是,如果你要经常调用这个作用域,我建议你使用内置的counter_cache

    class Response < ActiveRecord::Base
      belongs_to :candidate, counter_cache: true
      # ...
    end
    
    # add a migration
    add_column :candidates, :responses_count, :integer, default: 0
    
    # Candidate model
    class Candidate < ActiveRecord::Base
      scope :order_by_pending_responses, order('responses_count DESC')
      # ...
    end
    

    【讨论】:

    • 我不想使用 counter_cache 并且在 where 条件下您无法在列表中获得 完整的候选状态
    • 我不明白您所说的“无法在列表中获得完整的候选状态”是什么意思。不是left_joins解决了吗?
    猜你喜欢
    • 1970-01-01
    • 2016-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多