Fastest way to search two models connected via join table in rails given large data set
-
I have a user model and a cd model connected through a join table 'cds_users'. I'm trying to return a hash of users plus each cd they have in common with the original user. @user.users_with_similar_cds(1,4,5) # => {:bob => [4], :tim => [1,5]} Is there a better/faster way of doing this without looping so much? Maybe a more direct way? def users_with_similar_cds(*args) similar_users = {} Cd.find(:all, :conditions => ["cds.id IN (?)", args]).each do |cd| cd.users.find(:all, :conditions => ["users.id != ?", self.id]).each do |user| if similar_users[user.name] similar_users[user.name] << cd.id else similar_users[user.name] = [cd.id] end end end similar_users end [addition] Taking the join model idea, I could do something like this. I'll call the model 'joined'. def users_with_similar_cds(*args) similar_users = {} Joined.find(:all, :conditions => ["user_id != ? AND cd_id IN (?)", self.id, args]).each do |joined| if similar_users[joined.user_id] similar_users[joined.user_id] << cd_id else similar_users[joined.user_id] = [cd_id] end end similar_users end Would this be the fastest way on large data sets?
-
Answer:
You could use find_by_sql on the Users model, and Active Record will dynamically add methods for any extra fields returned by the query. For example: similar_cds = Hash.new peeps = Users.find_by_sql("SELECT Users.*, group_concat(Cds_Users.cd_id) as cd_ids FROM Users, Cds_Users GROUP BY Users.id") peeps.each { |p| similar_cds[p.name] = p.cd_ids.split(',') } I haven't tested this code, and this particular query will only work if your database supports group_concat (eg, MySQL, recent versions of Oracle, etc), but you should be able to do something similar with whatever database you use.
MediaJunkie at Stack Overflow Visit the source
Other answers
Yap, you can, with only 2 selects: Make a join table model named CdUser (use has_many.. through) # first select cd_users = CdUser.find(:all, :conditions => ["cd_id IN (?)", args]) cd_users_by_cd_id = cd_users.group_by{|cd_user| cd_user.cd_id } users_ids = cd_users.collect{|cd_user| cd_user.user_id }.uniq #second select users_by_id = User.find_all_by_id(users_ids).group_by{|user| user.id} cd_users_by_cd_id.each{|cd_id, cd_user_hash| result_hash[:cd_id] = cd_users_hash.collect{|cd_user| users_by_id[cd_user.user_id]} } This is just an ideea, haven't tested :) FYI: http://railscasts.com/episodes/47-two-many-to-many
Vlad Zloteanu
Related Q & A:
- How to read large data set at hourly interval?Best solution by stackoverflow.com
- How do I create an HTML table, in jQuery, with JSON data?Best solution by Stack Overflow
- What's the best and fastest way to get rid of acne scars on the back and chest?Best solution by Yahoo! Answers
- What is the fastest way to burn a DVD?Best solution by Yahoo! Answers
- What's the fastest way to ship from USA to Japan?Best solution by Yahoo! Answers
Just Added Q & A:
- How many active mobile subscribers are there in China?Best solution by Quora
- How to find the right vacation?Best solution by bookit.com
- How To Make Your Own Primer?Best solution by thekrazycouponlady.com
- How do you get the domain & range?Best solution by ChaCha
- How do you open pop up blockers?Best solution by Yahoo! Answers
For every problem there is a solution! Proved by Solucija.
-
Got an issue and looking for advice?
-
Ask Solucija to search every corner of the Web for help.
-
Get workable solutions and helpful tips in a moment.
Just ask Solucija about an issue you face and immediately get a list of ready solutions, answers and tips from other Internet users. We always provide the most suitable and complete answer to your question at the top, along with a few good alternatives below.