【问题标题】:ActiveRecord sort model on attribute of last has_many relation基于最后一个 has_many 关系的属性的 ActiveRecord 排序模型
【发布时间】:2017-05-02 01:37:40
【问题描述】:

我已经为此研究了一段时间......我找不到一个优雅的解决方案。我有loansloans has_many :decisionsdecisions 有一个我关心的属性,叫做risk_rating

我想根据最近的决定(通常基于 created_at)对loans 进行排序,但按risk_rating 排序。

Loan.includes(:decisions).references(:decisions).order('decisions.risk_rating DESC') 不起作用...

我想要贷款...按他们最近决定的 risk_rating 排序。这似乎应该比现在更容易。

我目前正在像这样在数据库之外执行此操作,但它会占用时间和内存:

Loan.all.sort do |x,y| 
  x.decisions.last.try(:risk_rating).to_f <=> y.decisions.last.try(:risk_rating).to_f
end

我想展示我提出的答案的表现,以及不准确之处...

Benchmark.bm do |x|
  x.report{ Loan.joins('LEFT JOIN decisions ON decisions.loan_id = loans.id').group('loans.id').order('MAX(decisions.risk_rating) DESC').limit(10).map{|l| l.decisions.last.try(:risk_rating)} }
end

    user     system      total        real
0.020000   0.000000   0.020000 ( 20.573096)

=> [0.936775, 0.934465, 0.932088, 0.922352, 0.921882, 0.794724, 0.919432, 0.918385, 0.916952, 0.914938]

顺序不对。 0.794724 不合适。

在那个程度上......我只在建议的答案中看到一个属性。我没有看到连接 =/

【问题讨论】:

  • 你用的是什么数据库?
  • 我们正在使用 MySQL
  • @IlyaLavrov 如果你用 Arel 适当地抽象也没关系。 ;)
  • @brendandeere 你能具体描述一下它与我的问题有什么关系吗?我似乎无法获得与我正在寻找的结果集相匹配的结果。

标签: ruby-on-rails ruby activerecord


【解决方案1】:

好吧,看来我今晚要加班到很晚了,因为我忍不住跳了进去:

class Loan < ApplicationRecord
  has_many :decisions
  has_one :latest_decision, -> { merge(Decision.latest) }, class_name: 'Decision'
end

class Decision < ApplicationRecord
  belongs_to :loan

  def latest
    t1 = arel_table
    t2 = arel_table.alias('t2')

    # Self join based on `loan_id` prefer latest `created_at`
    join_on = t1[:loan_id].eq(t2[:loan_id]).and(
      t1[:created_at].lt(t2[:created_at]))

    where(t2[:loan_id].eq(nil)).joins(
      t1.create_join(t2, t1.create_on(join_condition), Arel::Nodes::OuterJoin)
    )
  end
end

Loan.includes(:latest_decision)

这不会排序,只是提供每笔贷款的最新决定。由于表别名,抛出一个引用access_codesorder 会使事情变得混乱。我现在没有时间解决这个问题,但我敢打赌,如果你查看 Arel 上的一些重要资源以及如何将它与 ActiveRecord 一起使用,你就能弄清楚。我真的很喜欢this one

【讨论】:

    【解决方案2】:

    首先让我们编写 sql-query 来选择必要的数据。 SO 包含一个可能对这里有所帮助的问题:Select most recent row with GROUP BY in MySQL。我最好的版本:

    SELECT loans.*
    FROM loans
    LEFT JOIN (
      SELECT loan_id, MAX(id) as id
      FROM decisions
      GROUP BY loan_id) d ON d.loan_id = loans.id
    LEFT JOIN decisions ON decisions.id = d.id
    ORDER BY decisions.risk_rating DESC
    

    此代码假设MAX(id) 给出组中最近行的id

    您可以通过此 Rails 代码执行相同的查询:

    sub_query = 
      Decision.select('loan_id, MAX(id) as id').
        group(:loan_id).to_sql
    
    Loan.
      joins("LEFT JOIN (#{sub_query}) d ON d.loan_id = loans.id").
      joins("LEFT JOIN decisions ON decisions.id = d.id").
      order("decisions.risk_rating DESC")
    

    很遗憾,我手头没有 MySQL,也无法尝试此代码。希望它会起作用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-06
      • 1970-01-01
      • 1970-01-01
      • 2016-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多