通过子方法对记录进行排序,并按其他关联进行分组

时间:2015-11-13 16:06:47

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

好的,所以这里是示例设置:

House有许多CompletedJobs属于单个Person

CompletedJobs有一个名为total_score的方法,它是根据模型中的数据动态生成的。输出是大于零的整数。例如:

@completed_job1.total_score    #>output: 25
@completed_job2.total_score    #>output: 13

我想要做的是根据最后2 CompletedJobs的汇总得分抓住前20名Houses,并返回Person的{​​{1}}名称做了他们。

示例伪代码如下所示:

House
  .last(2)
  .sort_by{ SUM_OF_COMPLETED_JOBS_GROUPED_BY_PERSON }
  .map{ [SUM_OF_PERSONS_JOB_SCORE, PERSON] }
  .first(20)

我尝试了几种方法(从House开始,从查询中的Person开始),但我真的很困惑如何对得分的总和进行分组由人,然后将它们映射到一个数组。

如何在SQL(伪代码)中完成它的另一个例子:

SELECT SUM(&:total_score), person_name
  FROM completed_jobs
    JOINS people ON completed_job.person_id = people.id
  WHERE completed_jobs.created_at > 1.week.ago ## < There are 2 per week,
                                               ##   so this would grab the 2 most recent
  GROUP_BY completed_job.person_id
  ORDER BY &:total_score DESC
  LIMIT 20

如有必要,我可以提供更多信息。

如何在Rails中组合此查询?

更新

以下查询适用于抓取CompletedJobs每个House

的每个列表
# For example, let's say we only have two houses
h1 = House.first
h2 = House.last

h1_a = h1.completed_jobs.sort_by(&:total_score).map{|cj| [cj.total_score, cj.person.name]}

h2_a = h2.completed_jobs.sort_by(&:total_score).map{|cj| [cj.total_score, cj.person.name]}

如何合并h1h2,然后按最高总分排序?

更新2

我能够像这样组合和求和值:

(h1_a + h2_a).group_by(&:last).map{|k,v| [k, v.map(&:first).inject(:+)]}

如何在一个查询中完成所有这些操作?我所做的一定确实有效,但看起来太黑了:)。

1 个答案:

答案 0 :(得分:1)

我不确定你想得到什么 - 一个SQL查询?还是简短的Ruby单行?

Ruby代码:

# load all data into memory
houses = House.all.includes(completed_jobs: :person).last(2)

# process all in memory
houses.flat_map(&:completed_jobs).sort_by(&:total_score).last(20).group_by(&:person)

SQL查询(我看到唯一的方法是进行子查询):

SELECT t.name, SUM(t.total_scope)
FROM (
  SELECT p.name, j.total_score
  FROM houses h           // may be this table is excessive but...
    JOIN completed_jobs j ON j.house_id = h.id
    JOIN persons p ON p.id = j.person_id
  WHERE j.created_at > :week_ago_parameter
  ORDER BY j.total_score
  LIMIT 20
) t
GROUP BY t.name