如何从下游对象子集涉及的复杂活动记录 has_many 中获取列表
How do you get a list from complex active record has_many involved from a subset of downstream objects
当在中间关系上实现多个外键时,我很难从分层父关系中获取所涉及的游戏列表。
给定 League 对象 NFC
,找到它的所有 Game 对象 [G1,G3,G4]
# id :integer not null, primary key
# name :string
class League
has_many :teams
# has_many :games, :through => :teams (Is there some way to do this?)
end
# id :integer not null, primary key
# team_name :string
# league_id :integer
class Team
belongs_to :league
has_many :home_games, :foreign_key => team_a_id, :source => :game
has_many :away_games, :foreign_key => team_b_id, :source => :game
end
# id :integer not null, primary key
# game_name :string
# team_a_id :integer not null
# team_b_id :integer not null
class Game
belongs_to :home_team, :class_name => Team
belongs_to :away_team, :class_name => Team
end
数据示例:
LEAGUE - TEAM - GAME
---------------------------------
AFC -
PATRIOTS -
Home Away
G1(PATRIOTS vs DALLAS)
G2(PATRIOTS vs PITTSBURG)
PITTSBURG -
G2(PATRIOTS vs PITTSBURG)
NFC -
DALLAS -
G1(PATRIOTS vs DALLAS)
G3(DALLAS vs GREENBAY)
G4(DALLAS vs SEATTLE)
GREENBAY
G3(DALLAS vs GREENBAY)
SEATTLE
G4(DALLAS vs SEATTLE)
答案将包含 Rails 4 合规答案。如果 Rails 4 替代方案效率非常低,则可能会特别考虑 RAILS 5 答案。
nfc = League.where(name: 'NFC').first
# <answer>
puts nfc.games
## array containing objects [G1,G2,G3]
我面临的挑战是 home_team
/ away_team
并结合来自外键的数据。
一个可能的解决方案是在 League
上定义一个 games
方法,该方法查找其中任一外键指向其中一支球队的所有比赛:
class League
has_many :teams
def games
Game.where('team_a_id in (:ids) or team_b_id in(:ids)', ids: teams.pluck(:id))
end
end
您可以使用 join
:
完成同样的事情
Game.joins('inner join teams on teams.id = games.team_a_id or teams.id = games.team_b_id').where('teams.league_id = ?', id)
我要给出答案,
因为@meagar 的第一个解决方案
需要两个 SQL 查询而不是一个(另外,如果联赛没有球队,那不是 SQL 语法错误吗?),
第二个解决方案将包含重复的 Game 实例
如果两支球队都来自同一个联盟。
总的来说,我尽量避免在我的可重用范围内加入,
因为他们强制查询进入某个 "shape"。
所以我会写这样的东西:
class Game
# ...
scope :for_league, ->(league_id) {
where(<<-EOQ, league_id)
EXISTS (SELECT 1
FROM teams t
WHERE t.id IN (games.team_a_id, games.team_b_id)
AND t.league_id = ?)
EOQ
}
# ...
end
顺便说一下,这种 SQL 技术被称为 "correlated sub-query"。我承认你第一次看到它时看起来很奇怪,但这是一件很正常的事情。您可以看到子查询 "reaches out" 引用 games
。您的数据库优化它应该没有问题(当然给定外键索引),但从概念上讲,它在 games
table.
中每行运行一次子查询
当在中间关系上实现多个外键时,我很难从分层父关系中获取所涉及的游戏列表。
给定 League 对象 NFC
,找到它的所有 Game 对象 [G1,G3,G4]
# id :integer not null, primary key
# name :string
class League
has_many :teams
# has_many :games, :through => :teams (Is there some way to do this?)
end
# id :integer not null, primary key
# team_name :string
# league_id :integer
class Team
belongs_to :league
has_many :home_games, :foreign_key => team_a_id, :source => :game
has_many :away_games, :foreign_key => team_b_id, :source => :game
end
# id :integer not null, primary key
# game_name :string
# team_a_id :integer not null
# team_b_id :integer not null
class Game
belongs_to :home_team, :class_name => Team
belongs_to :away_team, :class_name => Team
end
数据示例:
LEAGUE - TEAM - GAME
---------------------------------
AFC -
PATRIOTS -
Home Away
G1(PATRIOTS vs DALLAS)
G2(PATRIOTS vs PITTSBURG)
PITTSBURG -
G2(PATRIOTS vs PITTSBURG)
NFC -
DALLAS -
G1(PATRIOTS vs DALLAS)
G3(DALLAS vs GREENBAY)
G4(DALLAS vs SEATTLE)
GREENBAY
G3(DALLAS vs GREENBAY)
SEATTLE
G4(DALLAS vs SEATTLE)
答案将包含 Rails 4 合规答案。如果 Rails 4 替代方案效率非常低,则可能会特别考虑 RAILS 5 答案。
nfc = League.where(name: 'NFC').first
# <answer>
puts nfc.games
## array containing objects [G1,G2,G3]
我面临的挑战是 home_team
/ away_team
并结合来自外键的数据。
一个可能的解决方案是在 League
上定义一个 games
方法,该方法查找其中任一外键指向其中一支球队的所有比赛:
class League
has_many :teams
def games
Game.where('team_a_id in (:ids) or team_b_id in(:ids)', ids: teams.pluck(:id))
end
end
您可以使用 join
:
Game.joins('inner join teams on teams.id = games.team_a_id or teams.id = games.team_b_id').where('teams.league_id = ?', id)
我要给出答案, 因为@meagar 的第一个解决方案 需要两个 SQL 查询而不是一个(另外,如果联赛没有球队,那不是 SQL 语法错误吗?), 第二个解决方案将包含重复的 Game 实例 如果两支球队都来自同一个联盟。
总的来说,我尽量避免在我的可重用范围内加入, 因为他们强制查询进入某个 "shape"。 所以我会写这样的东西:
class Game
# ...
scope :for_league, ->(league_id) {
where(<<-EOQ, league_id)
EXISTS (SELECT 1
FROM teams t
WHERE t.id IN (games.team_a_id, games.team_b_id)
AND t.league_id = ?)
EOQ
}
# ...
end
顺便说一下,这种 SQL 技术被称为 "correlated sub-query"。我承认你第一次看到它时看起来很奇怪,但这是一件很正常的事情。您可以看到子查询 "reaches out" 引用 games
。您的数据库优化它应该没有问题(当然给定外键索引),但从概念上讲,它在 games
table.