【问题标题】:Include all ids in ActiveRecord query在 ActiveRecord 查询中包含所有 id
【发布时间】:2016-05-06 11:50:17
【问题描述】:

我正在开发一个游戏平台,我有以下(简化的)模型:

class Game < ActiveRecord:Base
  has_many :game_players
  has_many :players, through: :game_players
end

class Player < ActiveRecord:Base
  has_many :game_players
  has_many :games, through: :game_players
end

class GamePlayer < ActiveRecord:Base
  belongs_to :game
  belongs_to :player
end

我需要执行 ActiveRecord 查询,以查找特定用户组玩的所有游戏。例如,给定数据:

+---------+-----------+
| game_id | player_id |
+---------+-----------+
|      10 |        39 |
|      10 |        41 |
|      10 |        42 |
|      12 |        41 |
|      13 |        39 |
|      13 |        41 |
+---------+-----------+

我需要找到一种方法来确定 ID 为 39 和 41 的玩家在玩哪些游戏,在这种情况下,ID 为 10 和 13 的游戏。到目前为止我发现的查询是:

Game.joins(:players).where(players: {id: [39, 41]}).uniq

但是,此查询返回的是这些玩家中的任何一个玩过的游戏,而不是他们两个玩过的游戏。

【问题讨论】:

    标签: mysql ruby-on-rails ruby activerecord


    【解决方案1】:

    如果你可以执行两个查询并相交结果,你可以试试看:

    Game.joins(:players).where(players: {id: 39}) & Game.joins(:players).where(players: {id: 41}) 
    

    【讨论】:

    • 这行得通,但我希望执行 1 个 SQL 查询,因为玩家的数量可以任意大
    • Game.joins(:players).where(players: {id: 39}).where(players: {id: 41}) - 试试这样的
    【解决方案2】:

    这个函数更像是一个 SQL INTERSECT,并且应该给你在这种情况下你需要的结果:

    Game.joins(:players).where(players: {id: [39,41]}).group('"games"."id"').having('COUNT("games"."id") > 1')
    

    真的,神奇的发生是通过选择任一玩家正在玩的游戏,然后按game.id 分组,以将结果减少到结果组中有多个game.id 的游戏。它从 Rails 控制台产生以下结果:

     => #<ActiveRecord::Relation [#<Game id: 10, created_at: "2016-05-07 01:17:25", updated_at: "2016-05-07 01:17:25">, #<Game id: 13, created_at: "2016-05-07 01:17:25", updated_at: "2016-05-07 01:17:25">]>
    

    请注意,此解决方案仅返回游戏 10 和 13(基于示例数据)。手动验证显示只有第 10 场和第 13 场比赛让玩家 39 和 41 都在玩。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多