Rails:分组依据联接表

时间:2018-12-13 23:11:01

标签: ruby-on-rails join group-by

我正在尝试按委托连接表分组。我有一个任务表,每个任务都有一个project_id。以下代码在我的控制器中运行良好,可以按项目分组:

@task = Task.joins(:project).joins(:urgency).where(urgencies: {urgency_value: 7}).group_by(&:project_id)

这将返回一个哈希,其中的密钥是我加入的密钥,然后索引包含该组中的每个任务。然后,我可以遍历每个任务以检索其属性。

但是,每个项目都属于一个工作空间(通过workspace_id)。我想要的是具有相同的查询,但要按工作区分组。我的最终目标是创建一个表,该表在第一列中显示工作空间名称,在第二列中显示该工作空间的任务数。

我尝试了很多组合并搜索了很多论坛,但几个小时后仍然无法破解它。

1 个答案:

答案 0 :(得分:0)

如果您唯一的目标是获取每个工作区的任务计数,那么我认为您想要一个不同的查询。

@workspaces_with_task_counts = 
  Workspace
    .joins(:projects)
    .joins(:tasks)
    .select('workspaces.name, count(tasks.id) as task_count')
    .group(:workspace_id)

然后您可以像这样访问计数:

@workspaces_with_task_counts.each do |workspace|
  puts "#{workspace.name}: #{workspace.task_count}"
end

编辑1

我想这就是你想要的:

Workspace
  .joins(projects: { tasks: :urgencies })
  .where(urgencies: {urgency_value: 7})
  .group(:name)
  .count

这将导致一个哈希,其中包含所有具有至少一个任务的工作区,其中urgency_value为7(按名称),以及该工作区中的任务数:

{"workspace1"=>4, "workspace2"=>1}

编辑2

SQL无法在单个查询中返回详细信息和摘要信息。但是,我们可以获取所有数据,然后使用Ruby的group_by方法将其汇总到内存中:

Task
  .joins(project: :workspace)
  .includes(project: :workspace)
  .group_by { |task| task.project.workspace.name }

这将产生以下数据结构:

{
  "workspace1": [task, task, task],
  "workspace2": [task, task],
  "workspace3": [task, task, task, task]
}

但是,这样做是有代价的。在内存中分组是一个昂贵的过程。对该查询运行10,000次大约需要15秒。

事实证明,执行两个SQL查询实际上要快两个数量级,速度约为0.2秒。这是查询:

tasks = Task.joins(project: :workspace).includes(project: :workspace)
counts = tasks.group('workspaces.name').count

第一个查询将为您提供所有任务,并预加载它们相关的项目和工作区数据。第二个查询使用ActiveRecord的group子句构造SQL语句以汇总数据。它返回此数据结构:

{ "workspace1": 3, "workspace2": 2, "workspace3": 4 }

数据库在设置操作方面超级高效。在数据库中完成该工作几乎总是比在Ruby中快得多。