以has_many关系订购

我的Articles有很多Metrics 。 当Metric.name =“得分”时,我希望通过特定的Metric.value来订购Articles 。 ( Metric将各种文章统计信息记录为“名称”和“值”对。文章可以有多个度量标准,甚至多个“分数”,尽管我只对最近的排序感兴趣。)

 class Article has_many :metrics class Metric # name :string(255) # value :decimal(, ) belongs_to :article 

我正在努力写一个范围来做这个 – 任何想法? 像这样的东西?

 scope :highest_score, joins(:metrics).order('metrics.value DESC') .where('metrics.name = "score"') 

更新:

  • 一篇文章可以在metrics量表中存储许多“分数”(因为它们是按周/每月/每年等计算的),但我只对使用任何一篇文章的第一个(最近的)“分数”感兴趣。 Metric模型具有default_scope,可确保DESCending排序。

  • 修复了’metrics.value DESC’报价位置的拼写错误。

  • 与我的手机朋友uber rails hacker交谈,看起来我可能需要一个原始的SQL查询。 现在,我已经超越了我的脑袋……(如果有帮助,我正在使用Postgres。)

谢谢!

更新2:

感谢Erwin的SQL查询建议,我有一个原始的SQL查询,它有效:

 SELECT a.* FROM articles a LEFT JOIN ( SELECT DISTINCT ON (article_id) article_id, value FROM metrics m WHERE name = 'score' ORDER BY article_id, date_created DESC ) m ON m.article_id = a.id ORDER BY m.value DESC; article_list_by_desc_score = ActiveRecord::Base.connection.execute(sql) 

这给出了一个表示文章数据的哈希数组(但不是文章对象??)。

后续问题:

有什么方法可以将它转换回Rails的activerecord查询? (所以我可以在范围内使用它)

解决方案更新:

如果有人正在寻找最终的ActiveRecord查询 – 非常感谢Mattherick帮我解决了这个问题 。 最终的工作查询是:

 scope :highest_score, joins(:metrics).where("metrics.name" => "score").order("metrics.value desc").group("metrics.article_id", "articles.id", "metrics.value", "metrics.date_created") .order("metrics.date_created desc") 

感谢大家!

查询可以像这样工作:

 SELECT a.* FROM article a LEFT JOIN ( SELECT DISTINCT ON (article_id) article_id, value FROM metrics m WHERE name = 'score' ORDER BY article_id, date_created DESC ) m ON m.metrics_id = a.metrics_id ORDER BY m.value DESC; 

首先 ,检索子查询m每篇文章的name = 'score'的“最新” value 。 在此相关答案中对使用的技术的更多解释:

  • 选择每个GROUP BY组中的第一行?

你似乎成了一个非常基本的误解的受害者:

但我只对使用任何一篇文章中的第一个(最近的)“得分”感兴趣。 度量标准模型具有default_scope,可确保DESCending排序。

表中没有“自然顺序” 。 在SELECT ,您需要ORDER BY定义良好的标准。 出于此查询的目的,我假设列metrics.date_created 。 如果您没有这种类型,则无法定义“最新”,并且被迫从多个符合条件的行中回退到任意选择:

  ORDER BY article_id 

可靠。 Postgres会挑选一排。 可能会随着表的任何更新或查询计划中的任何更改而更改。

接下来LEFT JOIN到表articleORDER BY valueNULL排序最后,所以没有限定值的文章最后。

注意:一些不那么聪明的ORM(我担心Ruby的ActiveRecord就是其中之一)使用非描述性和非独特的id作为主键的名称。 您必须适应您未提供的实际列名称。

性能

应该体面。 就Postgres而言,这是一个“简单”的查询。 表metrics部分多列索引会使其更快:

 CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created) WHERE name = 'score'; 

按此顺序排列。 在PostgreSQL 9.2+中,您可以添加列值以使仅索引扫描成为可能:

 CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created, value) WHERE name = 'score';