Sql Rails:在3个模型上进行复杂搜索,只返回最新的-如何做到这一点?

Sql Rails:在3个模型上进行复杂搜索,只返回最新的-如何做到这一点?,sql,ruby-on-rails,postgresql,ruby-on-rails-3.2,Sql,Ruby On Rails,Postgresql,Ruby On Rails 3.2,我正在尝试向我的应用程序添加一个高级搜索选项,用户可以根据3种不同型号的属性搜索某些链接 我的应用程序设置为用户有多个:网站,网站有多个:链接,链接有多个:统计数据 我知道如何在Rails中创建带有连接或包含等的SQL查询,但我陷入了困境,因为我只想检索每个链接的最新统计数据,而不是所有链接的最新统计数据,我不知道最有效的方法 例如,假设一个用户有两个网站,每个网站有10个链接,每个链接有100个统计数据,总共有2022个对象,但我只想搜索42个对象(每个链接只有1个统计数据) 一旦我在数据库查

我正在尝试向我的应用程序添加一个高级搜索选项,用户可以根据3种不同型号的属性搜索某些链接

我的应用程序设置为
用户有多个:网站
网站有多个:链接
链接有多个:统计数据

我知道如何在Rails中创建带有连接或包含等的SQL查询,但我陷入了困境,因为我只想检索每个链接的最新统计数据,而不是所有链接的最新统计数据,我不知道最有效的方法

例如,假设一个用户有两个网站,每个网站有10个链接,每个链接有100个统计数据,总共有2022个对象,但我只想搜索42个对象(每个链接只有1个统计数据)

一旦我在数据库查询中只得到了这42个对象,我就可以添加
.where(“类似属性?”,用户输入)
,并返回正确的链接

更新 我已尝试将以下内容添加到我的链接模型中:

has_many :stats, dependent: :destroy
has_many :one_stat, class_name: "Stat", order: "id ASC", limit: 1
但这似乎不起作用,例如,如果我这样做:

@links = Link.includes(:one_stat).all

@links.each do |l|
  puts l.one_stat.size
end
我得到的不是
1,1,1…
而是所有统计数据的编号:
125,40,76…

我可以使用“限制”选项来获得我想要的结果吗?还是不可以

第二次更新 我已经根据Erez的建议更新了代码,但仍然无法正常工作:

has_one :latest_stat, class_name: "Stat", order: "id ASC"

@links = Link.includes(:latest_stat)

@links.each do |l|
  puts l.latest_stat.indexed
end

=> true
=> true
=> true
=> false
=> true
=> true
=> true

Link.includes(:latest_stat).where("stats.indexed = ?", false).count
=> 6

Link.includes(:latest_stat).where("stats.indexed = ?", true).count
=> 7
它应该返回1和6,但它仍在检查所有统计信息,而不是只检查最新的统计信息。

我会尝试以下方法:

has_one :latest_stat, class_name: "Stat", order: "id ASC"

@links = Link.includes(:latest_stat)

@links.each do |l|
  puts l.latest_stat
end
注意:您无法打印最新的统计大小,因为它是统计对象本身,而不是关系。

我会尝试以下方法:

has_one :latest_stat, class_name: "Stat", order: "id ASC"

@links = Link.includes(:latest_stat)

@links.each do |l|
  puts l.latest_stat
end

注意:您不能打印最新的统计大小,因为它是统计对象本身而不是关系。

这就是您要查找的吗

@user.websites.map { |site| site.links.map { |link| link.stats.last } }.flatten

对于给定用户,这将返回一个数组,其中包含该用户网站上链接的最新统计信息

这就是你要找的吗

@user.websites.map { |site| site.links.map { |link| link.stats.last } }.flatten

对于给定用户,这将返回一个数组,其中包含该用户网站上链接的最新统计信息

有时,您必须突破AR抽象,启动SQL。就一点点

让我们假设你有非常简单的关系:
网站
有很多:链接
链接
属于:网站,
有很多:统计
统计
属于:链接。任何地方都没有非规范化。现在,您需要构建一个查询,该查询将查找它们的所有链接,并为每个链接查找最新的统计数据,但只能查找具有某些属性的统计数据(也可以是具有某些属性的网站或具有某些属性的链接)

未经测试,但类似于:

Website
  .includes(:links => :stats)
  .where("stats.indexed" => true)
  .where("stats.id = (select max(stats2.id) 
     from stats stats2 where stats2.link_id = links.id)")
最后一位子选择属于每个链接的统计信息并查找最大id。然后,它过滤掉与最大id不匹配的统计信息(从顶部的连接)。查询返回网站,每个网站都有一定数量的链接,每个链接在其
stats
集合中只有一个统计信息

一些额外信息

我最初写这个答案的时候用的是,这被证明是过分的,但我想我还是应该在这里讨论一下,因为,嗯,很有趣。您会注意到,我们上面使用的聚合函数技巧之所以有效,是因为我们根据它的ID来确定要使用哪个stat,而这个ID正是我们从联接中筛选stats所需的属性。但假设您只需要根据ID以外的一些标准排名的第一个统计数据,例如,
点击次数
;这一技巧将不再有效,因为聚合将无法跟踪ID。这就是窗口功能的用武之地

同样,完全未经测试:

Website
  .includes(:links => :stats)
  .where("stats.indexed" => true)
  .where(                                 
     "(stats.id, 1) in (
       select id, row_number() 
       over (partition by stats2.id order by stats2.number_of_clicks DESC)
       from stat stats2 where stats2.link_id = links.id
     )"
   )

最后一个
,其中
子选择与每个链接相匹配的统计信息,并按单击次数的升序排列,然后部分中的
将其与连接中的统计信息相匹配。请注意,窗口查询不能移植到其他数据库平台。您还可以使用此技术来解决您提出的原始问题(只需将
stats2.id
交换为
stats2.u点击次数
);可以想象,它的性能会更好,这正是它所提倡的。

有时,您必须突破AR抽象,并启动SQL。就一点点

让我们假设你有非常简单的关系:
网站
有很多:链接
链接
属于:网站
有很多:统计
统计
属于:链接。任何地方都没有非规范化。现在,您需要构建一个查询,该查询将查找它们的所有链接,并为每个链接查找最新的统计数据,但只能查找具有某些属性的统计数据(也可以是具有某些属性的网站或具有某些属性的链接)

未经测试,但类似于:

Website
  .includes(:links => :stats)
  .where("stats.indexed" => true)
  .where("stats.id = (select max(stats2.id) 
     from stats stats2 where stats2.link_id = links.id)")
最后一位子选择属于每个链接的统计信息并查找最大id。然后,它过滤掉与最大id不匹配的统计信息(从顶部的连接)。查询返回网站,每个网站都有一定数量的链接,每个链接在其
stats
集合中只有一个统计信息

一些额外信息

我最初写这个答案的时候用的是,这被证明是过分的,但我想我还是应该在这里讨论一下,因为,嗯,很有趣。您会注意到,我们上面使用的聚合函数技巧之所以有效,是因为我们根据它的ID来确定要使用哪个stat,而这个ID正是我们从联接中筛选stats所需的属性。但假设您只需要根据ID以外的一些标准排名的第一个统计数据,例如,
点击次数
;这一技巧将不再有效,因为聚合将无法跟踪ID。这就是窗口功能的用武之地

同样,完全未经测试:

Website
  .includes(:links => :stats)
  .where("stats.indexed" => true)
  .where(                                 
     "(stats.id, 1) in (
       select id, row_number() 
       over (partition by stats2.id order by stats2.number_of_clicks DESC)
       from stat stats2 where stats2.link_id = links.id
     )"
   )
最后一个
,其中
子选择与每个链接相匹配的统计信息,并按单击次数的升序排列,然后部分中的
将其与连接中的统计信息相匹配。注意,窗口