Here''s the problem I have the following models
User - is a person
Team - is a team
Wherenote - snipet of info about a user''s whereabouts on a certain day
Team has_and_belongs_to_many :users
User has_and_belongs_to_many :teams
has_many :wherenotes
Wherenote belongs_to :user
each Wherenote has a note_date
On one page I want to pull back all the Users from a particular Team and
then display all their Wherenotes for a given day.
Currently this is done by getting team.users and then doing a separate
find for
each of the users looking for Wherenotes with a particular note date.
The dreaded n+1 problem.
Teams are only quite small 10-30 users, and on any given day each user
only has a maximum of around 5 Wherenotes, however, as you can imagine
firing this number of database queries isn''t ideal.
I have tried to get round this by eager loading Wherenotes with each
user, but this causes a separate problem, as, over time, each user has
built up quite a stack of Wherenotes and eager loading them all takes up
too much time and memory.
Inside my team model I have written the following function.
<code>
def find_users_and_notes_from_date(date)
sql = ""
sql += "SELECT distinct u.*, w.* "
sql += "FROM whereusers u, wherenotes w, teams t, teams_users tu "
sql += "WHERE u.id = tu.user_id "
sql += "AND w.user_id = u.id "
sql += "AND w.note_date = " +
date.strftime(''\''%d-%b-%y\'''') + "
"
sql += "AND tu.team_id = " + self.id.to_s
User.find_by_sql sql
end
</code>
From my controller I call
<code>
@users = @team.find_users_and_notes_from_date(@date)
</code>
If I run the SQL code on it''s own then it brings back all the users and
and the notes for that Date and Team
Somewhere along the lines it''s all going wrong and I''m a
little far out
of my depth to work out where, or even if what I''m doing is possible.
If this is the wrong way to approach this problem or you can suggest a
way of making it working, I''d appreciate any help.
Thanks
Tom Styles
--
Posted via http://www.ruby-forum.com/.
--~--~---------~--~----~------------~-------~--~----~
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-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk
-~----------~----~----~----~------~----~------~--~---
I''m not sure what "goes wrong" but this is another way to
write the query.
I didn''t see where your teams table comes into play in your query, so I
left
it out:
SELECT DISTINCT u.*, w.*
FROM whereusers u
INNER JOIN teams_users tu
ON tu.user_id = u.id
AND tu.team_id = #{self.id.to_s}
INNER JOIN wherenotes w
ON w.user_id = u.id
AND w.note_date = yourdate
You could also try
User.find( :all, :conditions => "users.id = #{self.id} AND
teams_users.note_date = ''YOURDATE''", :include =>
[:teams, :wherenotes] )
or something similar...
ed
On 9/28/06, Tom Styles
<rails-mailing-list-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org>
wrote:>
>
> Here''s the problem I have the following models
>
> User - is a person
> Team - is a team
> Wherenote - snipet of info about a user''s whereabouts on a certain
day
>
> Team has_and_belongs_to_many :users
> User has_and_belongs_to_many :teams
> has_many :wherenotes
> Wherenote belongs_to :user
>
> each Wherenote has a note_date
>
> On one page I want to pull back all the Users from a particular Team and
> then display all their Wherenotes for a given day.
>
> Currently this is done by getting team.users and then doing a separate
> find for
> each of the users looking for Wherenotes with a particular note date.
> The dreaded n+1 problem.
>
> Teams are only quite small 10-30 users, and on any given day each user
> only has a maximum of around 5 Wherenotes, however, as you can imagine
> firing this number of database queries isn''t ideal.
>
> I have tried to get round this by eager loading Wherenotes with each
> user, but this causes a separate problem, as, over time, each user has
> built up quite a stack of Wherenotes and eager loading them all takes up
> too much time and memory.
>
> Inside my team model I have written the following function.
> <code>
> def find_users_and_notes_from_date(date)
> sql = ""
> sql += "SELECT distinct u.*, w.* "
> sql += "FROM whereusers u, wherenotes w, teams t, teams_users tu
"
> sql += "WHERE u.id = tu.user_id "
> sql += "AND w.user_id = u.id "
> sql += "AND w.note_date = " +
date.strftime(''\''%d-%b-%y\'''') + "
"
> sql += "AND tu.team_id = " + self.id.to_s
> User.find_by_sql sql
> end
> </code>
>
> From my controller I call
> <code>
> @users = @team.find_users_and_notes_from_date(@date)
> </code>
>
> If I run the SQL code on it''s own then it brings back all the
users and
> and the notes for that Date and Team
>
> Somewhere along the lines it''s all going wrong and I''m a
little far out
> of my depth to work out where, or even if what I''m doing is
possible.
>
> If this is the wrong way to approach this problem or you can suggest a
> way of making it working, I''d appreciate any help.
>
> Thanks
> Tom Styles
>
> --
> Posted via http://www.ruby-forum.com/.
>
> >
>
--
Ed Hickey
Developer
Litmus Media
816-533-0409
ehickey-A4HEbNdjHgMmlAP/+Wk3EA@public.gmane.org
A Member of Think Partnership, Inc
www.ThinkPartnership.com
Amex ticker symbol: THK
--~--~---------~--~----~------------~-------~--~----~
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-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk
-~----------~----~----~----~------~----~------~--~---
> I didn''t see where your teams table comes into play in your query, so I > leftNice one ed I wasn''t using the team table as you rightly pointed out> You could also try > > User.find( :all, :conditions => "users.id = #{self.id} AND > teams_users.note_date = ''YOURDATE''", :include => [:teams, :wherenotes] ) >This seemed more like it, not quite right, but much closer, so I''ve refiddled it into this user_ids = @team.users.collect{|u| u.id} @users = User.find(:all, :conditions => ["whereusers.id IN (?) AND wherenotes.note_date = ?", user_ids, @date.strftime("%d-%b-%y").upcase], :include => [:wherenotes]) This produces some SQL which, when executed, brings back exactly what I''m looking for, thus giving the impression that Rails is on top of the situation. However when it comes to returning an array of user objects I just get an empty array. This page http://api.rubyonrails.com/classes/ActiveRecord/Associations/ClassMethods.html Says that what I''m trying to do is impossible using activerecord, so How can it be done? Any additional help is really appreciated, Thanks Tom -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ 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-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk -~----------~----~----~----~------~----~------~--~---
Maybe I''m not quite understanding the problem.....but it seems to me
that
associations can go a long way to help you out
@team = Team.find :first, :include=>[{:users => :wherenotes}],
:conditions =>["wherenotes.note_date = ?", @date.strftime
("%d-%b-%y").upcase]
Untested, but includes can be nested which should get you want you want.
@team.users gives you all users
@team.user[0].wherenotes gives you the notes for that user
@team.users.each do |u|
u.wherenote.note_date
end
If I''m missing something, let me know and I can take another stab at
it. :)
Good luck!
On 10/11/06, Tom Styles
<rails-mailing-list-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org>
wrote:>
>
>
> > I didn''t see where your teams table comes into play in your
query, so I
> > left
>
> Nice one ed I wasn''t using the team table as you rightly pointed
out
>
> > You could also try
> >
> > User.find( :all, :conditions => "users.id = #{self.id} AND
> > teams_users.note_date = ''YOURDATE''", :include
=> [:teams, :wherenotes] )
> >
>
> This seemed more like it, not quite right, but much closer, so
I''ve
> refiddled it into this
>
> user_ids = @team.users.collect{|u| u.id}
>
> @users = User.find(:all, :conditions => ["whereusers.id IN (?) AND
> wherenotes.note_date = ?", user_ids,
@date.strftime("%d-%b-%y").upcase],
> :include => [:wherenotes])
>
> This produces some SQL which, when executed, brings back exactly what
> I''m looking for, thus giving the impression that Rails is on top
of the
> situation. However when it comes to returning an array of user objects I
> just get an empty array.
>
> This page
>
>
http://api.rubyonrails.com/classes/ActiveRecord/Associations/ClassMethods.html
> Says that what I''m trying to do is impossible using activerecord,
so How
> can it be done?
>
> Any additional help is really appreciated,
> Thanks
> Tom
>
>
> --
> Posted via http://www.ruby-forum.com/.
>
> >
>
--~--~---------~--~----~------------~-------~--~----~
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-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk
-~----------~----~----~----~------~----~------~--~---
Brian Hogan wrote:> Maybe I''m not quite understanding the problem.....but it seems to me > that > associations can go a long way to help you out > > > @team = Team.find :first, :include=>[{:users => :wherenotes}], > :conditions =>["wherenotes.note_date = ?", @date.strftime > ("%d-%b-%y").upcase]When I run this it just returns nil, I don''t think I can do this using associations and includes, because I need to include conditions on the included object. This is not where eager loading can be used. So I''m now thinking that a better way of doing it would be:- @users = @team.users user_ids = @users.collect{|u| u.id} wherenotes = Wherenote.find(:all, :conditions => ["user_id IN (?) AND note_date = ?", user_ids, @date], :order => ''user_id, position'') for user in @users for wherenote in wherenotes if wherenote.user_id == user.id user.wherenotes << wherenote end end end This seems to be working and populating an array of users with the correct wherenotes. The work is being done on the server rather than with multiple calls to the database. However now when I call user.wherenotes in the view instead of just bringing back the wherenotes that I''ve already loaded, it goes and does a fresh call to the database and brings back all the wherenotes for that user. Active record is being too helpful. I really need to cut the connection to the database at this point and force the object to work with what it''s got rather than do a fresh query. Any tips anyone. Tom -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ 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-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk -~----------~----~----~----~------~----~------~--~---
Okay, I''ve been watching this conversation play out for a while now. Tom, I''d like to point out something you''re saying which is completely false (and most likely holding you back from reaching a solution): "I need to include conditions on the included object. This is not where eager loading can be used" Eager loading using the :include option *absolutely* allows you to have conditions that refer to the relations specified in your :include. Not to put too fine a point on it, but what you''ve described so far is a *trivial* use-case of ActiveRecord. It''s time you started assuming you are doing something wrong rather than assuming ActiveRecord is incapable. Assuming what you''ve explained so far is accurate, try this. Tail the development.log file to see the queries being executed: x = Team.find(:all, :include => :users) x.first.users.length # should not cause another query to hit the DB y = Team.find(:all, :include => :users, :conditions =>''users.id is not null'') y.first.users.length # again, no extra hit to DB That''s your starting point. Regards, Trevor -- Trevor Squires http://somethinglearned.com On 10/12/06, Tom Styles <rails-mailing-list-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> > Brian Hogan wrote: > > Maybe I''m not quite understanding the problem.....but it seems to me > > that > > associations can go a long way to help you out > > > > > > @team = Team.find :first, :include=>[{:users => :wherenotes}], > > :conditions =>["wherenotes.note_date = ?", @date.strftime > > ("%d-%b-%y").upcase] > > When I run this it just returns nil, I don''t think I can do this using > associations and includes, because I need to include conditions on the > included object. This is not where eager loading can be used. > > So I''m now thinking that a better way of doing it would be:- > > @users = @team.users > user_ids = @users.collect{|u| u.id} > wherenotes = Wherenote.find(:all, :conditions => ["user_id IN (?) > AND note_date = ?", user_ids, @date], :order => ''user_id, position'') > for user in @users > for wherenote in wherenotes > if wherenote.user_id == user.id > user.wherenotes << wherenote > end > end > end > > This seems to be working and populating an array of users with the > correct wherenotes. The work is being done on the server rather than > with multiple calls to the database. > > However now when I call user.wherenotes in the view instead of just > bringing back the wherenotes that I''ve already loaded, it goes and does > a fresh call to the database and brings back all the wherenotes for that > user. > > Active record is being too helpful. I really need to cut the connection > to the database at this point and force the object to work with what > it''s got rather than do a fresh query. > > Any tips anyone. > > Tom > > -- > Posted via http://www.ruby-forum.com/. > > > >--~--~---------~--~----~------------~-------~--~----~ 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-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk -~----------~----~----~----~------~----~------~--~---