2016-04-28 53 views
1

我有兩個型號,讓我們稱之爲父母與子女,其中過濾一個的has_many的孩子/ belongs_to的關係,並得到所有他們的父母以及

class Parent < ActiveRecord::Base 
    has_many :child 
end 

class Child < ActiveRecord::Base 
    belongs_to :parent 
end 

對於一個API,我很感興趣,返回所有與特定條件匹配的子對象的列表,以及父代ID及其相應的父對象(但僅限過濾後的子對象的父代!),而不重複。

喜歡的東西:

{children: [{id: 1, parent_id: 20, attr1: x, attr2: y},...], parents: [{id: 20, attr3: z, attr4: w},...]} 

會是什麼這樣做是最有效的方法是什麼?

我曾嘗試做:

children = Child.eager_load(:parent).where(condition).all 
parents = children.map(&:parent).uniq{|p| p.id} 

但使用地圖和uniq的的有些慢,浪費了?

或者,我可以用兩個SQL查詢分別對它們進行查詢,即

children = Child.where(condition).all 
parent_ids = children.map(&:parent_id) 
parents = Parent.where(id: parents_ids).all 

然而,由於可能會有成百上千的不同的父母,這似乎仍然有點低效。

有沒有更好的方法?

回答

1

嘗試使用pluck

children = Children.eager_load(:parent).where(condition).all 
parents = children.pluck('distinct parent_id') 

編輯

推動這一到數據庫中,我誤解了這個問題。還有一個選擇,但我不確定它比運行所有的更好(比如你在問題中顯示的)或者運行多個查詢(就像你需要與pluck一樣)。你可以使用Set來確保父對象的唯一性:

parents = Set.new 
children = Children.eager_load(:parent).where(condition).all 
children.each {|child| parents << child.parent } 
+0

返回一個所有父ID的數組,類似於我提到的第二種可能性,對吧?如果我想要真正的父母親呢?我應該做'Parent.where(id:parents).all'嗎? – rpinheiro

+0

是的,它返回一個父親ID的數組。它取代了'parents = children.map(&:parent).uniq {| p |如果你還想要父對象,你必須重新查詢數據庫。在Ruby中枚舉數千個對象應該足夠快,適用於大多數用例,所以如果您需要它們的ID和父對象,您可能希望以這種方式急於加載父對象並獲取它們的ID(外觀就像你知道如何做到這一點:) – teubanks

+0

'parents = children.map(&:parent).uniq {| p | (注意它的**&:parent **而不是**&:parent_id **),沒有第二個SQL查詢(因爲它們已經被加載)。我不確定它是否非常有效(由於同時使用map和uniq),因此我的問題。 – rpinheiro

相關問題