Älphä Blüë
2009-Jul-19 23:26 UTC
Concerns about multiple model queries and array management
Wow, what a week! I''ve gotten a lot accomplished with my site but
brain-fried has set into my head..
I''m reaching a point where I''m having to manipulate arrays to
gain
access to ids that I will use in model.find methods.
Here''s a quick and probably dirty example of what works. I''m
only
showing it here because I know it''s gotta be dirty and ugly and
there''s
probably a better way of doing it, but I can''t seem to figure it out.
My best guess is I should be using each and each_with_index but anyhoo..
Providing the methods as is, with a brief idea of what data is
returned..
open_schedule = Schedule.new
opp_scheduled_ids = []
120.times do |i|
opp_scheduled_ids[i+1] = open_schedule.find_opponents(i+1)
puts "Team ID = #{i+1} and Scheduled IDs are
#{opp_scheduled_ids[i+1].join('','')} and Array Size
#{opp_scheduled_ids[i+1].size}"
end
This looks into my schedule model/table, finds 120 teams and any
opponent they''ve scheduled within date > datetime value and date
<
datetime value. It then returns the ids for those opponents. Data looks
like this:
Team ID = 1 and Scheduled IDs are
25,27,65,120,6,62,119,92,109,100,121,111,9 and Array Size = 13
Team ID = 2 and Scheduled IDs are
54,85,51,29,110,116,106,22,19,113,48,49 and Array Size = 12
Team ID = 3 and Scheduled IDs are
100,58,52,91,27,68,74,111,115,32,118,54 and Array Size = 12
Team ID = 4 and Scheduled IDs are
121,99,78,89,105,33,35,108,73,92,103,56 and Array Size = 12
etc...
So, I''m able to hold the Team ID for the team I''m checking,
and all of
their opponent_ids that they''ve scheduled based off whatever date
parameters I''ve selected. opponent_id is a foreign key that really is
the same as team_id but in an opponent''s column.
So far so good. Again, might be sloppy..
Now I want to pull out each of the opponent_ids that are stored in each
team''s array..
120.times do |i|
opp_scheduled_ids[i+1].size.times do |x|
puts "Team ID = #{i+1} and opp_id = #{opp_scheduled_ids[i+1][x]}"
end
end
This gives me the correct information that I''m looking for:
Team ID = 1 and opp_id = 25
Team ID = 1 and opp_id = 27
Team ID = 1 and opp_id = 65
Team ID = 1 and opp_id = 120
Team ID = 1 and opp_id = 6
Team ID = 1 and opp_id = 62
Team ID = 1 and opp_id = 119
Team ID = 1 and opp_id = 92
Team ID = 1 and opp_id = 109
Team ID = 1 and opp_id = 100
Team ID = 1 and opp_id = 121
Team ID = 1 and opp_id = 111
Team ID = 1 and opp_id = 9
Team ID = 2 and opp_id = etc.....
etc....
So, what I plan on doing is issuing a find method for each opponent id
to find out a rating in a specific table and sum them all up. The find
method will go in this laste method that I showed you that only houses a
puts statement so far..
But, as you can see that method is very ugly...
What can I do to clean it up so that it still does the same thing but
with cleaner code or efficiency? Again, my purpose is to learn better
array management with rails, especially since I will be doing a find
command.
In addition, my concerns are that I could probably just do "one" find
command for all of the rating values in a specific table and then search
within those results, matching up the opponent_id to the team_id and the
value..
Example:
I want to search for the totals for team_id in offense ratings table.
Do a find(:all) to pull all totals in offense ratings table.
Find the totals for opp_id = # where team_id = #...
This would be better, IMO, because I''m not pulling 120 separate queries
but one large query and searching in the cached results... correct?
Any advice will be greatly "appreciated" regarding my concerns..
Hey Marnen.. I remembered :)
--
Posted via http://www.ruby-forum.com/.
Älphä Blüë
2009-Jul-20 02:01 UTC
Re: Concerns about multiple model queries and array management
http://pastie.org/551660 I added a pastie of the current rake file task (yep still working on a procedural piece for ratings automation), along with the model (in full for schedules) etc. A brief idea of how it works and what I don''t like about it... In order to obtain a ratings schedule of strength for each team, I need to find all of the ratings for each team they play... This is why scheduling is so important to my project.. So, I''m simply finding all opponents for each team, then finding all the ratings for each opponent, and at the moment just doing a simple sum. It will get a lot more difficult as I place it into my Standard deviation variance model but I can do it. I just don''t like the "way" I''m doing it.. Look in the pastie code and there''s a small notes section right after the rake file. There''s one bit of code which looks enormously ugly and inefficient but it matches and works 100%! The cliche is if it''s not broke don''t fix it. But, even though it''s not broke, it just doesn''t feel rails like to me or ruby like to me. It feels hackish. This code here for instance: val += opp_off_tsos[opp_scheduled_ids[i+1][x]-1] .. what!!? Well break it down.. opp_off_tsos (translates to array for the rating itself) opp_scheduled_ids[i+1][x] (translates to the opponent_id) .... i+1 is because the 120.times starts with 0 and I need to start with 1.. .... x is a true 0 start because I used .each.. Why -1 at the end? Because the opp_off_tsos array was created with 120.times so it starts with 0 and I need to subtract one from the id to get it to match.. Again, it all works but as you can see, inefficient and ugly.. -- Posted via http://www.ruby-forum.com/.
Älphä Blüë
2009-Jul-20 03:33 UTC
Re: Concerns about multiple model queries and array management
Not sure if anyone is reading any of this, but figured I would update it
to show what things I''m doing to try and resolve my own code and clean
it up.
First, I took a step back and realized I was doing too much in my rake
file, and not enough in the model. So, all I have in my rake file for
this particular ratings bit is:
update_tsrs = TsrsRating.new
offensive_opponent_ratings = []
offensive_opponent_ratings = update_tsrs.calculate_ratings(Schedule,
TsosOffense)
offensive_opponent_ratings.each_with_index do |row,i|
puts " Team ID of #{i+1} has opponent ratings of #{row}"
end
that''s it...
The model then does all of the real work and returns the end result back
to the rake file to be held in queue until all the tallies are
completed.
I also realized that I wasn''t keeping things DRY. I should have
created
a class for the entire routine - so I did. I created a class that holds
the entire routine and made it so that I can call it with the remainder
of my ratings subtasks..
This should help.
I also realized that it doesn''t matter what my array and variable names
are so long as they are easy to read. Before they weren''t. I was even
getting lost myself.
So, I made them simpler to read using names like:
opponent_strength
opponent_array
opponent_ids
find_opponent_by_id
etc.
So, now I can at least read my own code which is hopefully a good thing.
I still have the same times loops and array loops in my code as I listed
in pastie. I will have to work at cleaning that up as well.
Thanks.
--
Posted via http://www.ruby-forum.com/.
On Sun, Jul 19, 2009 at 10:01 PM, Älphä Blüë <rails-mailing-list-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> > http://pastie.org/551660 > >I haven''t investigated all of this, and I''m coming from a Java/Groovy background and new to Rails, but when I see 120.times to me it throws up a red flag. Can''t you make this more OO? For example I would think you could say Find all teams and for each team there would be a collection of "opponents." (I remember a while back we had a discussion on the model for this project but forgot how it was resolved.) I would think the query itself would take care of a lot of this to avoid certain array constructs. I''d think lines 10-13 would just become teams = Teams.find(:all) (where in each time you''d have collection opponents ) Then later, something like: teams.each do |team| val = 0 team.opponents.each do |opponent| if opponent.schedule_id == 121 val += 0.2511 else val += opp_off_tsos[opponent.id] end end end Maybe I''m missing something (and I''m sure I am) but it sure seems cleaner using nested collections than doing all that array stuff.
Marnen Laibow-Koser
2009-Jul-20 05:12 UTC
Re: Concerns about multiple model queries and array management
Älphä Blüë wrote: [...]> Providing the methods as is, with a brief idea of what data is > returned..I don''t have time to review all these in depth, but:> > open_schedule = Schedule.new > opp_scheduled_ids = [] > 120.times do |i|Why are you hard-coding the value 120?> opp_scheduled_ids[i+1] = open_schedule.find_opponents(i+1) > puts "Team ID = #{i+1} and Scheduled IDs are > #{opp_scheduled_ids[i+1].join('','')} and Array Size > #{opp_scheduled_ids[i+1].size}" > end >Wow. Notice first of all that you''re using i+1 a lot in each iteration. If that''s even necessary -- and I''m not sure why it would be -- then you should put into a variable. In any case, your times loop is probably unnecessary; each_with_index would be better. Or if find_opponents could take a Team object as argument rather than an I''d value, you could use collect to slim this down even more.> This looks into my schedule model/table, finds 120 teams and any > opponent they''ve scheduled within date > datetime value and date < > datetime value. It then returns the ids for those opponents.You''re reinventing DB queries in the application layer. This should probably be done in the DB. [...]> Now I want to pull out each of the opponent_ids that are stored in each > team''s array.. > > 120.times do |i| > opp_scheduled_ids[i+1].size.times do |x|size.times? Why not each_with_index?> puts "Team ID = #{i+1} and opp_id = #{opp_scheduled_ids[i+1][x]}" > end > endWhy the i+1 all over the place? If you really need to start from 1, use (1..120).each. But it would probably be cleaner to use AR and/or a DB query for this. [...]> What can I do to clean it up so that it still does the same thing but > with cleaner code or efficiency?Stop trying to write Rails like spaghetti PHP! Learn to get the most out of Ruby''s Array methods (there are *lots*) and ActiveRecord. Get used to doing big queries in the DB. [...]> In addition, my concerns are that I could probably just do "one" find > command for all of the rating values in a specific table and then search > within those results, matching up the opponent_id to the team_id and the > value.. > > Example: > > I want to search for the totals for team_id in offense ratings table. > Do a find(:all) to pull all totals in offense ratings table. > Find the totals for opp_id = # where team_id = #... > > This would be better, IMO, because I''m not pulling 120 separate queries > but one large query and searching in the cached results... correct?Probably. Aggregate functions will make your life much easier here.> > Any advice will be greatly "appreciated" regarding my concerns.. > > Hey Marnen.. I remembered :)I see! LOL. Best, -- Marnen Laibow-Koser http://www.marnen.org marnen-sbuyVjPbboAdnm+yROfE0A@public.gmane.org -- Posted via http://www.ruby-forum.com/.
Älphä Blüë
2009-Jul-20 12:27 UTC
Re: Concerns about multiple model queries and array management
Thanks guys - I''m going to look at cleaning this up a bit. The 120
stems from the fact that there will always be exactly 120 teams (well
until the year 2012-2013) when South Alabama joins Div. 1.
My initial problem started when I didn''t understand how to organize two
arrays into a hash of hashes and sort through them. The example given
used 120.times and I kind of inherited that mechanic going forward. In
hindsight, I knew it felt wrong but I just didn''t get to the cleanup.
My focus problem with ruby iteration is understanding .each and
.each_with_index when handling array of arrays.
When querying data from a model it''s stored into an array. When using
each you iterate through each row and the value passed to the block is
used for iterating through that row.
example = model.find(:all)
example.each do |row|
puts "id = #{row.id} and name = #{row.name}"
end
Correct? Seems simple enough.. however,..
What if I have an array of arrays:
First glance I would think I would use each_with_index to handle an
array of arrays. But, I believe I''ve been having trouble using that
because by using times in the way that I have been some arrays are
populated and starting with 1 versus 0.
I''ll try cleaning up the code and post a cleanup version for you to
look
at to see if I''m progressing correctly.
Thanks again.
--
Posted via http://www.ruby-forum.com/.
Älphä Blüë
2009-Jul-20 13:07 UTC
Re: Concerns about multiple model queries and array management
Okay I just want to make sure I understand this better.
schedules = Schedule.find(:all)
schedules.each do |schedule|
puts "Team Id = #{schedule.team_id}"
end
That shows me all the team_ids listed in the schedules table. Now what
if I want to iterate through those team_ids and collect all of their
opponent ids together?
team Id 1 -> Opponent Id 3
team Id 1 -> Opponent Id 94
etc.
Each team has more than one opponent scheduled. The id fields are
team_id and opponent_id.
I tried:
schedules = Schedule.find(:all)
schedules.each do |schedule|
schedule.team_id.each do |team|
puts "Team Id = #{schedule.team_id} and Opponent Id =
#{team.opponent_id}"
end
end
But that will give me no method each found for 6:fixnum because I''m
trying each on a team_id number..
How do I further iterate through each row returned to gather up the
data? I want to know what opponent_ids each team_id has.
--
Posted via http://www.ruby-forum.com/.
Why don''t you just set the model up where you find "Teams" and each Team has a collection of Team objects called ''opponents''? It would seem to be a lot easier to me this way. On Mon, Jul 20, 2009 at 9:07 AM, Älphä Blüë<rails-mailing-list-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> That shows me all the team_ids listed in the schedules table. Now what > if I want to iterate through those team_ids and collect all of their > opponent ids together?This part seems pretty messed up. I think what Marnen and I are trying to say is why not aggregate this more? Why are so determined to work off of "ids" ? In my opinion you should be going through "Team" objects and not ids. And then for any given Team you''d have a nested collection of "opponents" ActiveRecord I''m sure could bring all this back to you in a more OO way. For example, what was wrong with my pseduo code idea: teams.each do |team| val = 0 team.opponents.each do |opponent| if opponent.schedule_id == 121 val += 0.2511 else val += opp_off_tsos[opponent.id] end end end
Älphä Blüë
2009-Jul-20 13:49 UTC
Re: Concerns about multiple model queries and array management
Hi Rick,
I want to do it exactly the way you are saying but I think I''m just a
bit confused here.
Let me show you what I''m working with now:
schedules = Schedule.find(:all, :joins => [:team, :opponent], :order =>
:team_id)
schedules.each do |schedule|
puts "Name = #{schedule.team.name} and ID = #{schedule.team.id} and
Opponent = #{schedule.opponent.id}"
end
I need to work out of schedules because there will be say 1,200 rows of
data. The teams table only contains 120 rows (for each team).
The associations I created were setup as:
class Schedule < ActiveRecord::Base
belongs_to :team
belongs_to :opponent, :class_name => "Team"
end
class Team < ActiveRecord::Base
has_many :schedules
has_many :inheritance_templates
has_many :opponents, :through => :schedules
has_many :tsos_offenses
has_many :tsos_defenses
has_many :tsos_steams
has_many :tsos_turnover_margins
has_many :tsrs_ratings
end
The above method does join both pieces together with teams. I''m just
unsure of how to iterate through them.
I tried what you said using opponent and even team as the next each
iteration but got no method each for those two..
--
Posted via http://www.ruby-forum.com/.
Älphä Blüë
2009-Jul-20 14:12 UTC
Re: Concerns about multiple model queries and array management
Rick,
I was also looking at your example - this is what I would like to do:
schedules = Schedule.find(:all, :joins => [:team, :opponent,
:tsos_offense], :order => :team_id)
schedules.each do |schedule|
val = 0
schedule.opponents.each do |opponent|
if opponent.id == nil
val += 0.2511
else
val += schedule.tsos_offenses.totals
puts "Team name = #{schedule.team.name} and opp_id =
#{schedule.opponent.id} and sum of val now = #{val} pulled from original
value of #{schedule.tsos_offense.totals}."
end
puts "Team"
end
end
When it comes down to it, each team, opponent has a ratings assigned to
team_id in tsos_offense. So, couldn''t I just somehow join the ratings
tables with schedules and setup all the information side by side and
iterate through it?
Example diagram:
Team has ..
id
name
Schedule has ..
team_id
opponent_id
Tsos Offense has ..
team_id
totals
=====================================Name | team_id | opponent_id | totals
=====================================
What would I have to do in tsos_offense to make the association work and
is my loop above correct once the association is in place?
--
Posted via http://www.ruby-forum.com/.
Älphä Blüë
2009-Jul-20 15:01 UTC
Re: Concerns about multiple model queries and array management
Let me take a step back here and look over my associations: Are they setup incorrectly? I want team to be my core object always.. class Team < ActiveRecord::Base has_many :schedules has_many :inheritance_templates has_many :opponents, :through => :schedules has_many :tsos_offenses has_many :tsos_defenses has_many :tsos_steams has_many :tsos_turnover_margins has_many :tsrs_ratings end I want schedule to be a part of teams and also to be a part of opponent (self-referential) through Team.. class Schedule < ActiveRecord::Base belongs_to :team belongs_to :opponent, :class_name => "Team" end These two pieces alone should give me associations between Team > Schedule > Opponent. My ratings tables all belong to team: class TsosOffense < ActiveRecord::Base belongs_to :team end class TsosDefense < ActiveRecord::Base belongs_to :team end class TsosSpecialTeams < ActiveRecord::Base belongs_to :team end class TsosTurnoverMargin < ActiveRecord::Base belongs_to :team end Everyone and everything I read, including you both (Rick and Marnen) say that large queries are much better than smaller queries. What if I want to query everything from all models listed here, assign them to a team object so that I can reference them by the team object. How would I do that? If I have the answer to this one question, I think I can fix all of the current issues I''m experiencing. -- Posted via http://www.ruby-forum.com/.
Älphä Blüë
2009-Jul-20 15:02 UTC
Re: Concerns about multiple model queries and array management
> class TsosSpecialTeams < ActiveRecord::Base > belongs_to :team > end.. is actually supposed to read: class TsosSteams belongs_to :team end -- Posted via http://www.ruby-forum.com/.
I''ve been busy the past two days. How have things worked out with all this? On Mon, Jul 20, 2009 at 11:01 AM, Älphä Blüë < rails-mailing-list-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> > Let me take a step back here and look over my associations: > > Are they setup incorrectly? > > I want team to be my core object always.. > > class Team < ActiveRecord::Base > has_many :schedules > has_many :inheritance_templates > has_many :opponents, :through => :schedules > has_many :tsos_offenses > has_many :tsos_defenses > has_many :tsos_steams > has_many :tsos_turnover_margins > has_many :tsrs_ratings > end > > I want schedule to be a part of teams and also to be a part of opponent > (self-referential) through Team.. > > class Schedule < ActiveRecord::Base > belongs_to :team > belongs_to :opponent, :class_name => "Team" > end > > These two pieces alone should give me associations between Team > > Schedule > Opponent. > > My ratings tables all belong to team: > > class TsosOffense < ActiveRecord::Base > belongs_to :team > end > class TsosDefense < ActiveRecord::Base > belongs_to :team > end > class TsosSpecialTeams < ActiveRecord::Base > belongs_to :team > end > class TsosTurnoverMargin < ActiveRecord::Base > belongs_to :team > end > > Everyone and everything I read, including you both (Rick and Marnen) say > that large queries are much better than smaller queries. > > What if I want to query everything from all models listed here, assign > them to a team object so that I can reference them by the team object. > How would I do that? > > If I have the answer to this one question, I think I can fix all of the > current issues I''m experiencing. > > > -- > Posted via http://www.ruby-forum.com/. > > > >-- Rick R --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Älphä Blüë
2009-Jul-23 00:49 UTC
Re: Concerns about multiple model queries and array management
The associations were fine. I did find a way to implement my ratings system and it works solidly. I built everything in the models and now I only use rake files for task/procedure initialization. The models all house the meat of my routines/methods for calculations. -- Posted via http://www.ruby-forum.com/.