我有一个带有一些 has_many 关联的 Post 模型。
class Post < ActiveRecord::Base
...
has_many :votes
has_many :comments
has_many :ratings
end
我想要一个按 (votes.count + comments.count + ratings.count
) 对帖子排序的查询。
例如,如果我的帖子有 3 票、2 条评论和 1 个评分,其排序“指标”的值为 6。我该怎么做?
我还想要第二个查询,它使用相同的 3 个参数(投票、评论、评级)对其进行排序,但还添加了与 created_at
成反比的第 4 个参数,因此较新的帖子将是排名靠前,较旧的帖子排名较低。总之,排序指标类似于:
(F*(1/created_at) + votes.count + comments.count + ratings.count
),其中 F 是比例因子。我该怎么做?
最佳答案
我建议您使用 AR counter cache这里:
4.1.2.4 :counter_cache
The
:counter_cache
option can be used to make finding the number of belonging objects more efficient.
[...]
Although the:counter_cache
option is specified on the model that includes thebelongs_to
declaration, the actual column must be added to the associated model.
因此,您需要修改相应的 belongs_to
声明以包含 :counter_cache
选项:
class Vote < ActiveRecord::Base
belongs_to :post, :counter_cache => true
end
# Similarly for the other two...
然后在迁移中将计数器列添加到您的 posts
表中:
def change
change_table :posts do |t|
t.integer :votes_count
#...
end
end
您还需要一个迁移来为您现有的 Post
初始化计数器。
然后您会将计数器作为模型的属性,您可以这样说:
Post.where(...).order('posts.votes_count + posts.comments_count + posts.ratings_count')
如果你想包含 created_at
那么你可以使用 extract(epoch from created_at)
获取时间戳作为方便的 double 值,您可以在算术表达式中使用它。
这样做的缺点是,如果您偏离了 The One True Path To Rails Nirvana(或者它真正要去的地方;)的一根头发,计数器可能会不同步,所以您需要小心不要自己接触数据库,并始终通过关联来创建和销毁事物。我还建议您构建一个快速的'n'dirty 健全性检查器,您可以不时运行它以确保计数器正确。
如果你很高兴成为 PostgreSQL 特定的,那么你可以放弃 :counter_cache => true
废话和它带来的所有脆弱性,并在数据库中使用触发器来维护缓存的计数器值(value)观。
关于ruby-on-rails - Rails 查询中的自定义排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16028601/