ActiveRecord查找包含至少一个项目的类别

时间:2011-11-22 13:26:20

标签: ruby-on-rails ruby-on-rails-3 activerecord

支持我有多个项目和类别的模型,采用多对多关系

class Item < ActiveRecord::Base
  has_and_belongs_to_many :categories 

class Category < ActiveRecord::Base
  has_and_belongs_to_many :items

现在我想过滤掉至少包含一个项目的类别,最好的方法是什么?

4 个答案:

答案 0 :(得分:2)

我想回应@Delba的答案并对其进行扩展,因为它是正确的 - 如果您正确设置了索引,那么@huan的儿子建议使用count列是完全没必要的。

我想补充一点,你可能想使用.uniq,因为它是多对多你只想要DISTINCT类别回来:

Category.joins(:items).uniq

使用联接查询可以让您更轻松地将条件用于项目计数,从而提供更大的灵活性。例如,您可能不想计算enabled = false的项目:

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
祝你好运, 斯图

答案 1 :(得分:1)

Category.joins(:items)

此处有更多详情:http://guides.rubyonrails.org/active_record_querying.html#joining-tables

答案 2 :(得分: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"

答案 3 :(得分:0)

请注意,其他人的回答是不是很好!

性能最佳的解决方案:

最好使用 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(items是复数化的has_many类名)

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

在has_and_belongs_to_many关系中你必须像上面那样把它写成你自己的