2016-11-05 84 views
0

A pool_tournament有許多pool_tournament_matches,每個匹配屬於多個users。用戶has_many pool_tournaments和has_many pool_tournament_matches如何在單個查詢中獲得此查詢結果而不是N + 1

pool_tournament.rb

has_many :pool_tournament_matches 

pool_tournament_match.rb

belongs_to :pool_tournament 
has_many :pool_tournament_match_users, class_name: 'PoolTournamentMatchUser' 
has_many :users, through: :pool_tournament_match_users 

user.rb

has_many :pool_tournament_users, class_name: 'PoolTournamentUser' 
has_many :pool_tournaments, through: :pool_tournament_users 

has_many :pool_tournament_match_users, class_name: 'PoolTournamentMatchUser' 
has_many :pool_tournament_matches, through: :pool_tournament_match_users 

有2的has_many通過協會在這裏。一個是在userpool_tournament之間。另一個是在pool_tournament_matchuser之間。

我的查詢是找出哪個pool_tournament_matches只有1個用戶。我的查詢向我提供了匹配列表,但它爲每個pool_tournament_match執行N + 1查詢。

tournament.pool_tournament_matches.includes(:users).select { |m| m.users.count == 1 } 

PoolTournamentMatch Load (0.6ms) SELECT "pool_tournament_matches".* FROM "pool_tournament_matches" WHERE "pool_tournament_matches"."pool_tournament_id" = $1 [["pool_tournament_id", 2]] PoolTournamentMatchUser Load (0.6ms) SELECT "pool_tournament_match_users".* FROM "pool_tournament_match_users" WHERE "pool_tournament_match_users"."pool_tournament_match_id" IN (1, 2, 3, 4) User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" IN (1, 2, 3, 4, 5, 6, 7, 8) (0.8ms) SELECT COUNT(*) FROM "users" INNER JOIN "pool_tournament_match_users" ON "users"."id" = "pool_tournament_match_users"."user_id" WHERE "pool_tournament_match_users"."pool_tournament_match_id" = $1 [["pool_tournament_match_id", 1]] (0.7ms) SELECT COUNT(*) FROM "users" INNER JOIN "pool_tournament_match_users" ON "users"."id" = "pool_tournament_match_users"."user_id" WHERE "pool_tournament_match_users"."pool_tournament_match_id" = $1 [["pool_tournament_match_id", 2]] (0.7ms) SELECT COUNT(*) FROM "users" INNER JOIN "pool_tournament_match_users" ON "users"."id" = "pool_tournament_match_users"."user_id" WHERE "pool_tournament_match_users"."pool_tournament_match_id" = $1 [["pool_tournament_match_id", 3]] (0.7ms) SELECT COUNT(*) FROM "users" INNER JOIN "pool_tournament_match_users" ON "users"."id" = "pool_tournament_match_users"."user_id" WHERE "pool_tournament_match_users"."pool_tournament_match_id" = $1 [["pool_tournament_match_id", 4]]

我也不介意使用RAW SQL,如果需要,可以張貼架構。

謝謝!

+1

刪除我的答案,因爲它是不正確的。見http://stackoverflow.com/questions/16348333/rails-includes-with-conditions –

回答

1

您可以讓SQL爲您計數。下面以Postgres的應該工作(不知道其他數據庫):

tournament.pool_tournament_matches 
    .select("pool_tournament_matches.*, COUNT(users.id) as user_count") 
    .joins("LEFT OUTER JOIN pool_tournament_match_users ON (pool_tournament_match_users.pool_tournament_match_id = pool_tournament_matches.id)") 
    .joins("LEFT OUTER JOIN users ON (pool_tournament_match_users.user_id = users.id)") 
    .group("pool_tournament_matches.id") 
    .select { |match| match.user_count > 0 } 

一切行動和incuding的.group產生一個單一的查詢,並將它附加一個「USER_COUNT」屬性則返回pool_tournament_matches。因此,最後的.select發生在內存中,對結果進行解析而不進行額外的數據庫調用。

+0

你是一個救星!我會盡力瞭解您發佈的查詢,並希望在此更好! – okysabeni

+1

幾個月前,我在自己的項目中遇到了幾乎相同的問題,所以我只好去挖掘它並用您的表名替換我的表名。很高興它有幫助。 – moveson

相關問題