ruby-on-rails - Rails 查询中的自定义排序

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

我有一个带有一些 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 the belongs_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/

相关文章:

ruby-on-rails - Capistrano 3 - 处于多个角色时执行两次任务

ruby-on-rails - 如何在生产服务器中升级 rvm 和 ruby​​ 版本

python - SQLALchemy:查询 Postgres JSONB 列的单个键或键的子集

postgresql - 如何 pg_restore

ruby-on-rails - Ruby 中有类似 JS 'Promise.all()' 的东西吗?

ruby-on-rails - 如何忽略 Zeitwerk for Rails 6 中的文件夹?

ruby-on-rails - 错误: undefined method 'link_to_remote'

ruby-on-rails - 如何在 Rails 3.2 中使用 JBuilder 渲染 json

ruby-on-rails-3 - 在测试环境中设置 default_url_options 似乎不起作用

java - 出现错误 : cursor "<unnamed portal 1>" does not exist