2015-09-21 123 views
1

我遇到了rails activerecord查詢的問題。Rails有效地查詢記錄和最新關聯記錄,包括?

我有2個表格。

一個用於項目:

id | name | created_at | updated_at 

一個項目報告:

id | project_id | number | created_at | updated_at 

項目對應的類:

class Project < ActiveRecord::Base 
    has_many :project_reports 

    def latest_report_number 
    project_reports.last.number 
    end 
end 

而且ProjectReports:

class ProjectReport < ActiveRecord::Base 
    belongs_to :project 
end 

我在試圖編寫一個查詢來獲取項目列表和最近的項目報告。

我可以做到這一點通過以下方式,但是這導致了N + 1分的情況:

Project 
    .select("projects.*, max(project_reports.created_at) as latest_report") 
    .joins(:project_reports) 
    .order("latest_report desc") 
    .group("projects.id") 
    .map { |p| "#{p.name}: #{p.latest_report_number}" } 

爲此我想用軌「包括」功能,這樣我就不會遇到N個+1情況:

Project 
    .select("projects.*, max(project_reports.created_at) as latest_report") 
    .joins(:project_reports) 
    .order("latest_report desc") 
    .group("projects.id") 
    .includes(:project_reports) # <---- 
    .map { |p| "#{p.name}: #{p.latest_report_number}" } 

這使我的查詢不再起作用:

PG::GroupingError: ERROR: column "project_reports.id" must appear in 
the GROUP BY clause or be used in an aggregate function 

我怎麼能寫我的查詢這樣我就完成了目標,並限制了我打入數據庫的次數(理想情況下包含)?

+0

爲什麼不把project_reports和project.id放在一起? – Zahid

+0

因爲這不會爲我提供獨特的項目結果。同一個項目會在每個報告的結果集中出現多次。 –

+0

爲什麼在第二個查詢中使用'joins'和'includes'? – Pavan

回答

1

在加入查詢的情況下,includes要求關聯表中的額外列(即tasks),以便在沒有附加查詢的情況下構建關聯對象。通常情況下,這是一個受歡迎的優化,但在GROUP BY條款的情況下,最終結果是無效的SELECT

就你而言,你需要一個完全獨立的查詢來加載關聯,所以preload是一個更好的選擇。

Project 
    .select("projects.*, max(project_reports.created_at) as latest_report") 
    .joins(:project_reports) 
    .order("latest_report desc") 
    .group("projects.id") 
    .preload(:project_reports) 
    .map { |p| "#{p.name}: #{p.latest_report_number}" } 
+0

正是我在找的東西。謝謝你,先生! –