0

我正在开发一项搜索项目的功能。

我的模型大致是这样的:

User has many items
User has many addresses
User has one profile
Item has many images
Item has many addresses
Item belongs to category

我想显示按用户分组的结果,例如:

Results for 'Laptop':

Items of Bob:
  Laptop dell (details...)
  Samsung laptop (details...)

Items of Alice:
  Laptop HP (details...)
...

所以我有这个急加载的大查询:

r = User.includes([{items: [:images, :addresses, :category]}, :addresses, :profile]).
  joins(:items).
  where('query like "%laptop%"').
  where(...).
  limit(80).
  all
# then get the first page of results with kaminary

然后我在 erb 中显示这样的循环:

r.each do |u|
  # items of user u
  u.items do |i|
    # item i
  end
end

一切正常,除了急切加载需要很长时间。通过只加载第一页上显示的项目可以更快。

活动记录有可能只急切加载有条件的记录吗?像这样的东西:User.includes([:table1, table2], conditions: 'users.id in (1,2,3)')

另一种解决方案是执行限制为 20 的大请求,然后在限制为 80 的情况下重做请求而不预先加载,然后手动合并结果,但这很复杂吗?

还有其他建议吗?

4

1 回答 1

0

我最终做了两个请求并将结果合并在一起。这并不像听起来那么难:

# per_page is 20
limit = "#{(page.to_i - 1) * 20}, #{(page.to_i * 20)}"
query = Users.where('items.title LIKE "%whatever%"').where('addresses.lat < 50')
return query.includes([{items: [:images, :category]}, :profile, :addresses]).
    joins(:items).          
    limit(limit).all |
    query.select('DISTINCT users.*').joins(:items, :addresses).
    limit(200).all

备注1:

这个 Eager 只加载当前页面的 20 个元素,并添加其他页面上的所有元素而不进行 Eager 加载。例如,假设您在第 3 页,第一个请求将急切加载limit 60, 80并添加元素 #0 到 #199。ruby 中数组联合(运算符|)的工作方式是,如果两个数组中都存在相同的元素,则保留第一个数组中的元素。在这种情况下,第一个数组中的元素将预先加载元素。因此,如果我们在第三页,它将与 合并[60..80] (eager loaded)[1..200] (not eager loaded)最终数组中的元素 60 到 80 将是第一个数组中的元素。

备注2:

select distinct 很重要,因为没有它,限制将限制项目或地址的数量。例如,如果用户 #1 有 198 个对象,则第二个查询将返回如下内容:

  user 1 - item 1 of user 1
  user 1 - item 2 of user 1
  ...
  user 1 - item 198 of user 1
  user 2 - item 1 of user 2
  user 3 - item 1 of user 3

这不会正确预加载。合并后我们会有用户 [1, 2, 3, 60, 61, ... 80]。

有了不同的结果,结果将是:

  user 1 - item 1 of user 1
  user 2 - item 1 of user 2
  user 3 - item 1 of user 3
  ...
  user 200 - item 1 of user 200

合并后我们将有 [1, 2, 3... 200] ,其中元素 60 到 80 取自第一个查询。

备注 3:

在第二个查询中,我们必须连接 where 子句中使用的所有表。

于 2013-08-31T16:54:02.177 回答