2011-11-22 25 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 

祝你好运, 斯图

相关问题