ActiveRecord:包括组中的关联
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ActiveRecord:包括组中的关联相关的知识,希望对你有一定的参考价值。
我真的很喜欢ActiveRecord,但有时候我发现这些(相对)复杂的查询很有挑战性,而且我不知道如何寻求帮助。
这是我的方法:
def self.get_top_victims_for_player(player, count=10)
top_victims = player
.kills
.group(:victim)
.order('count_id DESC')
.limit(count)
.count(:id)
formatted = top_victims.map do |player, count|
{ "#{player.names.first.name} (#{player.steam_id})" => count}
end.reduce({}, :merge)
{ type: "list", data: formatted }
end
目标是获得所提供玩家杀人的受害者的前十名单。
这一行:{ "#{player.names.first.name} (#{player.steam_id})" => count}
创建了许多查询来检索每个玩家的相关Names
。我觉得如果我能够加载这个Name
协会,我可以在一个查询中检索每个玩家的第一个Name
。
这是运行方法时的日志:
D, [2017-12-18T23:49:11.324957 #26877] DEBUG -- : Player Load (0.3ms) SELECT "players".* FROM "players" WHERE "players"."id" = $1 LIMIT $2 [["id", 304], ["LIMIT", 1]]
D, [2017-12-18T23:49:11.332907 #26877] DEBUG -- : (5.2ms) SELECT COUNT("kills"."id") AS count_id, "kills"."victim_id" AS kills_victim_id FROM "kills" WHERE "kills"."player_id" = $1 GROUP BY "kills"."victim_id" ORDER BY count_id DESC LIMIT $2 [["player_id", 304], ["LIMIT", 10]]
D, [2017-12-18T23:49:11.335472 #26877] DEBUG -- : Player Load (0.6ms) SELECT "players".* FROM "players" WHERE "players"."id" IN (735, 96, 98, 893, 335, 213, 2801, 268, 1391, 3108)
D, [2017-12-18T23:49:11.338581 #26877] DEBUG -- : Name Load (1.1ms) SELECT "names".* FROM "names" WHERE "names"."player_id" = $1 ORDER BY "names"."id" ASC LIMIT $2 [["player_id", 735], ["LIMIT", 1]]
D, [2017-12-18T23:49:11.341112 #26877] DEBUG -- : Name Load (0.3ms) SELECT "names".* FROM "names" WHERE "names"."player_id" = $1 ORDER BY "names"."id" ASC LIMIT $2 [["player_id", 96], ["LIMIT", 1]]
D, [2017-12-18T23:49:11.343411 #26877] DEBUG -- : Name Load (0.9ms) SELECT "names".* FROM "names" WHERE "names"."player_id" = $1 ORDER BY "names"."id" ASC LIMIT $2 [["player_id", 98], ["LIMIT", 1]]
D, [2017-12-18T23:49:11.345129 #26877] DEBUG -- : Name Load (1.0ms) SELECT "names".* FROM "names" WHERE "names"."player_id" = $1 ORDER BY "names"."id" ASC LIMIT $2 [["player_id", 893], ["LIMIT", 1]]
D, [2017-12-18T23:49:11.346893 #26877] DEBUG -- : Name Load (1.1ms) SELECT "names".* FROM "names" WHERE "names"."player_id" = $1 ORDER BY "names"."id" ASC LIMIT $2 [["player_id", 335], ["LIMIT", 1]]
D, [2017-12-18T23:49:11.348842 #26877] DEBUG -- : Name Load (1.2ms) SELECT "names".* FROM "names" WHERE "names"."player_id" = $1 ORDER BY "names"."id" ASC LIMIT $2 [["player_id", 213], ["LIMIT", 1]]
D, [2017-12-18T23:49:11.351487 #26877] DEBUG -- : Name Load (1.6ms) SELECT "names".* FROM "names" WHERE "names"."player_id" = $1 ORDER BY "names"."id" ASC LIMIT $2 [["player_id", 2801], ["LIMIT", 1]]
D, [2017-12-18T23:49:11.354888 #26877] DEBUG -- : Name Load (1.2ms) SELECT "names".* FROM "names" WHERE "names"."player_id" = $1 ORDER BY "names"."id" ASC LIMIT $2 [["player_id", 268], ["LIMIT", 1]]
D, [2017-12-18T23:49:11.357178 #26877] DEBUG -- : Name Load (1.6ms) SELECT "names".* FROM "names" WHERE "names"."player_id" = $1 ORDER BY "names"."id" ASC LIMIT $2 [["player_id", 1391], ["LIMIT", 1]]
D, [2017-12-18T23:49:11.358084 #26877] DEBUG -- : Name Load (0.2ms) SELECT "names".* FROM "names" WHERE "names"."player_id" = $1 ORDER BY "names"."id" ASC LIMIT $2 [["player_id", 3108], ["LIMIT", 1]]
阿森松时尚:
Player has_many :kills
Player has_many :names
Kill belongs_to :player
Kill belongs_to :victim, :class_name => 'Player', foreign_key: 'victim_id'
Name belongs_to :player
如何优化此方法?
(旁注:我在哪里可以了解更多相关信息?当我遇到与此类似的问题时,我应该使用哪些资源?)
为什么不创建另一个具有hmt关系的模型,当它们进入时会记录新的杀戮?新型号:UserKilledPlayers
:belongs_to :user
在用户模型中:
has_many :user_killed_players
has_many :killed_players, source: :user_killed_players, through: :users_killed_players
您的表格类似于:user_killed_players
user_id | killed_players_id | count
每次用户杀死另一个用户时,在++
上制作一个count
的方法。然后它只是一个简单的查询
UserKilledPlayer.where(user_id: current_user).order('max(count) DESC')
关于将用户与用户关联的更多细节有很多:here
这是一个在一个查询中检索数据的解决方案:
def self.get_top_victims_for_player(player_id, count=10)
sql_string = <<-EOS
with first_names as
( select distinct on (player_id) player_id, name
from names
order by player_id, id )
select players.steam_id, first_names.name, count(kills.id)
from kills
join first_names on kills.victim_id = first_names.player_id
join players on kills.victim_id = players.id
where kills.player_id = #{player_id}
group by kills.victim_id, first_names.name, players.steam_id
order by count(kills.id) desc
limit #{count}
EOS
res = connection.execute(sql_string)
res.map {|h| {"#{h['name']} (#{h['steam_id']})" => h["count"]} }
end
使用一些本地数据运行示例:
>> Player.get_top_victims_for_player(1)
(1.0ms) with first_names as
( select distinct on (player_id) player_id, name
from names
order by player_id, id )
select players.steam_id, first_names.name, count(kills.id)
from kills
join first_names on kills.victim_id = first_names.player_id
join players on kills.victim_id = players.id
where kills.player_id = 1
group by kills.victim_id, first_names.name, players.steam_id
order by count(kills.id) desc
limit 10
=> [{"name2 (2)"=>5}, {"name3 (3)"=>3}, {"name4 (4)"=>2}]
缺点是它由于CTE和DISTINCT ON而特定于PostgreSQL,并且它还有许多原始SQL。可能它可以通过一些工作制作更多Active Record-ish。
以上是关于ActiveRecord:包括组中的关联的主要内容,如果未能解决你的问题,请参考以下文章
使用 activerecord 发出请求以仅从组中获取用户,而不从其他人中获取
ActiveRecord、has_many :through 和多态关联