我试图通过created_at进行ORDER,然后根据外键获取DISTINCT集。
另一部分是以某种方式使用它是ActiveModelSerializer。具体来说,我希望能够声明:
has_many :somethings
在序列化程序中。让我进一步解释......
我能够通过这个自定义sql获得我需要的结果:
def latest_product_levels
sql = "SELECT DISTINCT ON (product_id) client_product_levels.product_id,
client_product_levels.* FROM client_product_levels WHERE client_product_levels.client_id = #{id} ORDER BY product_id,
client_product_levels.created_at DESC";
results = ActiveRecord::Base.connection.execute(sql)
end
是否有任何可能的方法来获得此结果,但作为has_many关系的一个条件,以便我可以在AMS中使用它?
在伪代码中:@ client.products_levels
会做类似的事情:@client.order(created_at: :desc).select(:product_id).distinct
当然,由于我之外的原因而失败。
任何帮助都会很棒。
谢谢。
答案 0 :(得分:3)
构建此问题的一种好方法是将查询分为两部分:第一部分管理行的过滤,以便您只获得最新的客户端产品级别。第二部分使用标准has_many
关联将Client
与ClientProductLevel
联系起来。
从您的ClientProductLevel
模型开始,您可以创建一个范围来执行最新的过滤:
class ClientProductLevel < ActiveRecord::Base
scope :latest, -> {
select("distinct on(product_id) client_product_levels.product_id,
client_product_levels.*").
order("product_id, created_at desc")
}
end
您可以在具有返回ClientProductLevel对象列表的查询的任何位置使用此范围,例如ClientProductLevel.latest
或ClientProductLevel.where("created_at < ?", 1.week.ago).latest
等。
如果您还没有这样做,请设置Client
关联has_many
课程:
class Client < ActiveRecord::Base
has_many :client_product_levels
end
然后在你的ActiveModelSerializer中试试这个:
class ClientSerializer < ActiveModel::Serializer
has_many :client_product_levels
def client_product_levels
object.client_product_levels.latest
end
end
当您调用ClientSerializer
序列化Client
对象时,序列化程序会看到has_many
声明,它通常会转发到您的Client
对象,但是因为我们通过该名称获得了本地定义的方法,它会调用该方法。 (请注意,此has_many
声明与ActiveRecord has_many
不同,它指定了表之间的关系:在这种情况下,它只是说序列化程序应该在键下呈现一系列序列化对象`client_product_levels'。)
ClientSerializer#client_product_levels
方法依次从客户端对象调用has_many
关联,然后将latest
范围应用于它。 ActiveRecord最强大的功能是它允许您将不同的组件链接到一个查询中。这里,has_many
生成`where client_id = $ X'部分,范围生成查询的其余部分。瞧瞧!
在简化方面:ActiveRecord没有对distinct on
的本机支持,所以你一直坚持使用自定义sql的那部分。我不知道您是否需要在您的select子句中明确包含client_product_levels.product_id
,因为它已被*
包含在内。您可以尝试转储它。