繁体   English   中英

Rails查询中的自定义排序

[英]Custom ordering in Rails query

我有一些has_many关联的Post模型。

class Post < ActiveRecord::Base
 ...
 has_many :votes
 has_many :comments
 has_many :ratings
end

我想要一个查询,以按( votes.count + comments.count + ratings.countvotes.count + comments.count + ratings.countvotes.count + comments.count + ratings.countvotes.count + comments.count + ratings.count )对帖子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计数器缓存

4.1.2.4:counter_cache

:counter_cache选项可用于更有效地查找所属对象的数量。
[...]
尽管:counter_cache选项是在包含belongs_to声明的模型上指定的,但实际的列必须添加到关联的模型中。

因此,您需要修改相应的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)来获取时间戳,作为方便的双精度值,可以在算术表达式中使用。


不利的一面是,如果您误入歧途,计数器可能会失去同步,而如果您从Rails Nirvana的真实路径(或实际发生的任何地方)发了疯,那么您需要注意不要触摸数据库。自己,并始终通过协会来创造和摧毁事物。 我还建议您构建一个快速运行的脏检查程序,该检查程序可以不时运行以确保计数器正确。

如果您愿意成为特定于PostgreSQL的对象,则可以:counter_cache => true废话以及它附带的所有易碎性,并使用数据库中的触发器来维护缓存的计数器值。

为什么需要在数据库中完成此操作? 如果不是,我建议您在找到所有记录及其包含的关联之后,使用sort_by ruby​​方法。 就像是:

# In the post model 
class Post < ActiveRecord::Base
  def custom_metric
    votes.size + comments.size + ratings.size
  end
end

# In post controller
@posts = Post.where(id: ..).includes(:votes, :comments, :ratings).sort_by(&:custom_metric)

您可以按照相同的逻辑类型对对象进行排序。 与建议的其他方法相比,该方法将很快,并且具有不会引起任何数据非规范化的优点。 该查询将始终返回所需的结果,而不管数据库的状态如何。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM