如何按照has_many关系中的对象数对Rails AR.find进行排序

如何编写AR查找查询以使结果按has_many关联中的记录数排序?

class User < ActiveRecord::Base has_many :photos end 

我想做点什么……

 User.find(:all, :order => photos.count) 

我发现我的发现不是有效的代码。 说我有以下数据。

 User 1, which has 3 photos User 2, which has 5 photos User 3, which has 2 photos 

我希望我的发现能够按照…的顺序将用户带回来

 User 2, User 1, User 3 

根据用户照片的数量

如果您不想要额外的列,则可以始终在返回的结果集中请求额外的列:

 User.all(:select => "#{User.table_name}.*, COUNT(#{Photo.table_name}.id) number_of_photos", :joins => :photos, :order => "number_of_photos") 

这会生成以下SQL:

 SELECT users.*, COUNT(photos.id) number_of_photos FROM `users` INNER JOIN `photos` ON photos.user_id = users.id ORDER BY number_of_photos 

实现此目的的最简单方法可能是向该模型添加计数器缓存,然后按该列排序。

 class Photo < ActiveRecord::Base belongs_to :user, :counter_cache => true end 

并确保在users表中添加一个名为photos_count的列。

然后你就可以……

 User.find(:all, :order => 'photos_count') 

如果您不想添加计数器缓存列,则唯一的选择是在查找后进行排序。 如果您:include在查找中:include关联,则不会产生任何其他数据库工作。

 users = User.find(:all, :include => :photos).sort_by { |u| -u.photos.size } 

注意sort_by块中的负号以从高到低排序。

我建议你不要编写直接SQL,因为它的实现可能因商店而异。 幸运的是,你有bel:

 User.joins(:photos).group(Photo.arel_table[:user_id]). order(Photo.arel_table[:user_id].count) 

计数器缓存会有所帮助,但您需要在数据库中添加一个额外的列。

我将此作为对最佳答案的评论添加,但我不能出于某种原因。 根据这篇文章:

http://m.onkey.org/active-record-query-interface

在Rails 3.0.3之后, User.all(options)方法将被弃用,并被一堆其他(方便的,可链接的)活动记录类型的东西所取代,但它很难弄清楚如何组合相同的类型查询。

结果,我继续前进并实现了计数器缓存方法。 除非您需要记住在迁移中更新列信息,否则这非常容易且无痛,否则所有现有记录都将为“0”。

这是我在迁移中使用的内容:

 class AddUserCountToCollections < ActiveRecord::Migration def self.up add_column :collections, :collectionusers_count, :integer, :default => 0 Collection.reset_column_information Collection.all.each do |c| Collection.update_counters c.id, :collectionusers_count => c.collectionusers.count end end def self.down remove_column :collections, :collectionusers_count end end 

从理论上讲,这也应该更快。 希望这对你有所帮助。

你的问题没有意义。 :order参数指定列名和可选的排序方向,即asc(结束)或desc(结束)。

你想要达到的结果是什么?