ActiveRecord分组通过加入

时间:2013-04-17 00:46:41

标签: ruby-on-rails activerecord

当我必须加入另一张桌子时,真的一直在努力让一群人上班。我可以在没有加入时让小组上班,但是当我想在另一张桌子上按专栏分组时,我开始遇到问题。

Tables:
Book
id, category_id

Category
id, name

ActiveRecord schema:

class Category < ActiveRecord::Base
  has_many :books
end

class Book < ActiveRecord::Base
  belongs_to :category
end

我正试图按类别计算得到一个小组。 I.E.我想知道每个类别中有多少本书。

我尝试了很多东西,这是最新的,

books = Book.joins(:category).where(:select => 'count(books.id), Category.name', :group => 'Category.name')

我希望得到像

这样的东西
[{:name => fiction, :count => 12}, {:name => non-fiction, :count => 4}]

有什么想法吗?

提前致谢!

2 个答案:

答案 0 :(得分:1)

如果您只是在每个类别中的书籍数量之后,您从has_many关联获得的关联方法可能就足够了(请查看Association Basics guide)。您可以使用

获取属于特定类别的图书数量
@category.books.size

如果你想构建你描述的数组,你可以用以下内容自己构建它:

array = Categories.all.map { |cat| { name: cat.name, count: cat.books.size } }

作为额外的一点,如果您经常查看某个类别中的图书数量,您可能还需要考虑使用计数器缓存,因此获取某个类别中的图书数量并不需要额外的数据库之旅。为此,您需要在图书模型中进行以下更改:

# books.rb
belongs_to :category, counter_cache: true

创建一个迁移来添加和初始化计数器缓存使用的列:

class AddBooksCountToCategories < ActiveRecord::Migration
  def change
    add_column :categories, :books_count, :integer, default: 0, null: false

    Category.all.each do |cat|
      Category.reset_counters(cat.id, :books)
    end
  end
end

编辑:经过一些实验,以下内容应该可以满足您的需求:

counts = Category.joins(:books).count(group: 'categories.name')

这将返回一个散列,其中类别名称为键,计数为值。您可以使用.map { |k, v| { name: k, count: v } }将其设置为您在问题中指定的格式。

我会密切注意这样的事情 - 一旦你拥有足够多的书籍,加入可能会使事情变得缓慢。使用counter_cache将始终是最高效的,并且对于足够多的书籍,急切加载两个单独的查询也可以提供更好的性能(这是使用includes的急切加载从使用更改的原因加入Rails 2.1中的多个查询。

答案 1 :(得分:0)

这个怎么样: Category.joins(:books).group("categories.id").count 它应返回一组键/值对,其中键表示类别ID,值表示与该类别关联的书籍数。