これにはいくつかの方法があります。4000 レコードというのは全体像としてはそれほど多くはありませんが、(質問で示唆したように) 複数のクエリでアクセスする必要がなくなるのは「良いこと」です。
解決策の鍵は、見たいアドレスをどのように選択するかです。「最初」は相対的であり、修飾子 (order by またはその他の属性) なしでは非決定論的です。
シンプルなアプローチ - has_one 関連付け
簡単なアプローチの 1 つは、has_one 関係を定義することです。
class User
has_many :addresses
has_one :primary_address, :class_name => 'Address', :conditions => ["primary = ?", true]
end
これは、ディサイダーを使用できる Address に属性があることを前提としています。条件を指定しない場合は、has_one が基になるクエリに SQL LIMIT 1 を適用するため、"最初に" 来るアドレス エントリが取得されます。
これにより、ユーザーと単一のアドレスの詳細を簡単に収集できます。
# iterating over users
User.scoped.each { |user| puts user.primary_address.area_code }
# or collect area_codes
area_codes = User.scoped.collect{ |user| user.primary_address.area_code }
ただし、これはまだ各行にアクセスしているため、すべてのユーザーのアドレスに対して余分なクエリ (および ruby 配列の処理) が必要になります。
はるかに良い - アレル
ユーザーが持っている可能性のある複数のアドレスから決定基準を選択したら、これを 1 つのクエリにまとめることができます。
min(id) で住所を選択するだけだと仮定すると (Rails 3 を使用していると仮定すると)、個別の area_codes をクエリするための Arel のアプローチは次のとおりです。
address = Address.arel_table
primary_addresses = Address.where(
address[:id].in(
address.group(address[:user_id]).project(address[:id].minimum)
)
)
primary_addresses は、ユーザーの「プライマリ」アドレスの完全なコレクションを提供するスコープです。その後、必要に応じて処理/リスト/収集できます。
area_codes = primary_addresses.collect(&:area_code)
クエリは実際に次のような SQL を生成します。
SELECT "addresses".*
FROM "addresses"
WHERE "addresses"."id" IN (
SELECT MAX("addresses"."id") AS max_id FROM "addresses" GROUP BY "addresses"."user_id"
)
ご覧のとおり、サブセレクトは、アドレス ID のリストを返しています。ユーザーごとに 1 つずつです。使用するアドレスを選択するために別の基準を使用する場合は、サブクエリを変更できます (たとえば、制限 1 で primary=true を選択するようにします)。