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

最終的に 2 つのリクエストを実行し、結果をマージしました。思ったほど難しくありません。

# 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:

このイーガー ロードは、現在のページの 20 要素のみをロードし、他のページのすべての要素をイーガー ロードなしで追加します。たとえば、3 ページ目にいるとします。最初のリクエストは で熱心にロードされlimit 60, 80、要素 #0 から #199 が追加されます。ruby での配列の結合 (演算子|) のしくみは、両方の配列に同じ要素が存在する場合、最初の配列の要素が保持されるというものです。この場合、最初の配列の要素が要素を熱心にロードします。したがって、3 ページ目にある場合、 とマージ[60..80] (eager loaded)[1..200] (not eager loaded)れ、最後の配列の要素 60 から 80 が最初の配列の要素になります。

備考 2:

個別の選択は重要です。これがないと、アイテムまたは住所の数が制限されてしまうからです。たとえば、ユーザー #1 が 198 個のオブジェクトを持っている場合、2 番目のクエリは次のような結果を返します。

  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:

2 番目のクエリでは、where 句で使用されるすべてのテーブルを結合する必要があります。

于 2013-08-31T16:54:02.177 に答える