4

当我不得不加入另一张桌子时,真的很难让一群人工作。当我不加入时,我可以让 group by 工作,但是当我想按另一张表上的列分组时,我开始遇到问题。

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

我正在尝试根据类别计数来分组。IE 我想知道每个类别有多少本书。

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

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

我希望得到类似的东西

[{:name => fiction, :count => 12}, {:name => non-fiction, :count => 4}]

有任何想法吗?

提前致谢!

4

2 回答 2

1

如果您只是在计算每个类别中的书籍数量,那么您从关联中获得的关联方法has_many可能就足够了(查看关联基础指南)。您可以使用以下方式获取属于特定类别的书籍数量

@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 } }它来完全按照您在问题中指定的格式。

不过,我会留意类似的事情——一旦你有足够多的书,加入可能会稍微减慢速度。usingcounter_cache总是性能最高的,对于足够多的书籍,使用两个单独的查询进行预加载也可能会给您带来更好的性能(这就是includes在 Rails 2.1 中使用连接进行预加载更改为多个查询的原因)。

于 2013-04-17T02:04:18.947 回答
1

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

于 2018-03-20T21:53:04.083 回答