2011-11-22 66 views
1

支持,我有兩個模型項目和類別分類,在許多一對多的關係ActiveRecord的發現包含至少一個項目

class Item < ActiveRecord::Base 
    has_and_belongs_to_many :categories 

class Category < ActiveRecord::Base 
    has_and_belongs_to_many :items 

現在我想篩選出其中至少包含一個項目類別,最好的辦法是什麼?

回答

0

請注意,其他人answererd是不是表演!

最高效的解決方案:

更好的工作與counter_cache並保存items_count模型!

scope :with_items, where("items_count > 0") 


has_and_belongs_to_many :categories, :after_add=>:update_count, :after_remove=>:update_count 

def update_count(category) 
    category.items_count = category.items.count 
    category.save 
end 

正常 「belongs_to的」 關係你只寫

belongs_to :parent, :counter_cache=>true 

,並在parent_model你有一個場items_count(項目是多元化的的has_many類名)

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

在has_and_belongs_to_many關係中,你必須按照你自己的方式寫出它

+0

它可能性能較差,但它依賴於RDBMS來保持一致性(它們專門爲此設計的)。根據Rails如何執行after_add回調(例如,它是否在事務中),最終可能導致計數不一致。 – ahlatimer

+0

您可以爲這些案例編寫測試,並將事務包裝在其中。那不是問題。但事實上:你有2500個類別,裏面都有10-500篇文章。你知道查詢有多大嗎? :) –

+0

你知道查詢有多大嗎?內部加入速度非常快,即使對於數千條記錄,您的保存也很少。並且您正在假設類別和項目被插入/添加的次數與它們被選擇的次數之間的關係。所以它*可能不會更高性能 – Stu

0
scope :has_item, where("#{table_name}.id IN (SELECT categories_items.category_id FROM categories_items") 

這將返回其具有在連接表項的所有類別,因爲表面上,一類不應該有一個入口那裏,如果它沒有一個物品。您可以將AND categories_items.item_id IS NOT NULL添加到子選擇條件中以確保。

如果您不知道,table_name是返回調用它的ActiveRecord類的表名稱的方法。在這種情況下,它將是"categories"

2

我想回應@ Delba的回答,並對其進行擴展,因爲它是正確的 - 如果你的索引設置正確,@huan兒子建議的count列是完全不必要的。

我想補充一點,你可能想使用.uniq,因爲它是一個多到許多你只是想不同的類別回來:

Category.joins(:items).uniq 

使用聯接查詢將讓你更輕鬆地工作將項目數量也考慮在內,給予更多的靈活性。例如,你可能不希望清點貨物,其中啓用=假:

Category.joins(:items).where(:items => { :enabled => true }).uniq 

這將生成的SQL語句,使用內部聯接這是非常快:

SELECT `categories`.* FROM `categories` INNER JOIN `categories_items` ON `categories_items`.`category_id` = `categories`.`id` INNER JOIN `items` ON `items`.`id` = `categories_items`.`item_id` WHERE `items`.`enabled` = 1 

祝你好運, 斯圖

相關問題