2014-05-06 7 views
-2
> Player.joins(:game).order('games.scheduled_start ASC').last(5).sum(:ppg) 

=> NoMethodError: undefined method `+' for #<GamePlayer:0x007ff543cd05d8> 


> Player.joins(:game).order('games.scheduled_start ASC').sum(:ppg) 

=> #<BigDecimal:7ff543cebc20,'0.30115E3',18(18)> 

Таким образом, я не понимаю, почему .last(n) нарушает мою способность вызывать .average и .sum на этой коллекции.рубин средней и сумма на последней (п)

EDIT

[19] pry(main)> GamePlayer.order('id desc').limit(10).map{|x| x.ppg.to_f} 
    GamePlayer Load (0.6ms) SELECT "game_players".* FROM "game_players" ORDER BY id desc LIMIT 10 
=> [14.0, 0.75, 1.2, 0.0, 2.55, 1.19, 2.04, 2.0, 0.0, 24.68] 

[20] pry(main)> GamePlayer.order('id desc').limit(10).average(:ppg).to_f 
    (74.4ms) SELECT AVG("game_players"."ppg") AS avg_id FROM "game_players" LIMIT 10 
=> 8.943831900603671 

[21] pry(main)> GamePlayer.order('id desc').limit(50).average(:ppg).to_f 
    (73.4ms) SELECT AVG("game_players"."ppg") AS avg_id FROM "game_players" LIMIT 50 
=> 8.943831900603671 

[22] pry(main)> GamePlayer.order('id desc').limit(50).map{|x| x.ppg.to_f}.sum/50 
    GamePlayer Load (0.9ms) SELECT "game_players".* FROM "game_players" ORDER BY id desc LIMIT 50 
=> 3.649800000000001 

Кто-нибудь есть идея, что это несоответствие составляет около?

ответ

4

Ну last(5) (или в более общем last(n)) представляет собой метод, определенный на Array, что означает, что ActiveRecord::Relation вы построить по телефону Player.joins(:game).order('games.scheduled_start ASC') будет оцениваться в массив, а затем last(5) будет вызываться, что в результате массив.

Rails добавляет возможность вызова sum на массив, но он будет работать по-другому, чем на ActiveRecord::Relation (по телефону + по каждому объекту и текущей суммы, начиная с 0).

Вместо этого вы, вероятно, захотите использовать это:

players = Player.joins(:game).order('games.scheduled_start DESC').limit(5) 
sum = Player.joins(:game).where(id: players).sum(:ppg) 

Обратите внимание, что я перешел от ASC к DESC, а предел всегда будет принимать элементы с самого начала. Теперь sum будет фактически переведен в соответствующую функцию SQL-агрегата, которая будет работать на :ppg -колонке. where -clause необходим для запуска подзапроса, чтобы sum выполнил только для тех игроков, которых выбрал limit.

Однако, если вы действительно хотите работать с массивом (который будет медленнее), вы можете использовать этот метод:

players = Player.joins(:game).order('games.scheduled_start ASC').last(5) 
# builds the sum of all ppg-values of all players selected 
sum = players.sum(&:ppg) 

Но average будет работать только на ActiveRecord::Relation, так как она не определена на Array (даже не в Rails). Вы можете, конечно, построить его самостоятельно, но опять же, метод ActiveRecord::Relation будет быстрее.

+0

Я не думаю, что вы можете использовать 'limit' и' sum' таким образом – Stefan

+1

Если я не ошибаюсь, 'SUM' возвращает одну строку, а' LIMIT' не имеет никакого эффекта. – Stefan

+0

он работал нормально ... однажды у меня был объект отношения, вызвавший 'average (: ppg)' работал отлично. – Dudo

Смежные вопросы