Hello.Let's say I have the following schemaPeople <---> people_services <---> servicesThat is, people has a many-to-many relationship with services. Say I want to find all people who has services of types 1 and 2. How can we do it on activerecord today?My best solution so far is thispeople_query = Person.joins(:services)people = [][1,2].each do |t|people << people_query.where(:type => 1)endpeople = people.reduce(:&)That's not so good because by doing reduce(:&) you're exiting activerecord domain. So you wouldn't be able to do something like people.reduce(:&).limit(10). Also, that way I'm loading a lot more data than I actually need in my application memory. So, certainly not optimal solution.It's possible to make such query in SQL alone, if the dbms supports INTERSECTION then doing it is straightforward. If it doesn't, it's still possible using joins on subqueries.
I think activerecord ought support such query and I'm willing to take my time and write the code for it. However, I'd like someone to help me out with it a bit. I don't understand rails or activerecord code base so well. Anyway, it would be best if I did a gem that introduces that feature into activerecord. Can anyone tell me what should I look up? A high level description of what I must do would be great. Something like "You'll need to create a gem, monkey patch this activerecord class, probably use this and this function to help you writing your SQL" would be nice.Cheers--
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group.
To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-core/-/jz3f6lJrXEkJ.
To post to this group, send email to rubyonra...@googlegroups.com.
To unsubscribe from this group, send email to rubyonrails-co...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-core/-/9t0fM-NiDdEJ.
To post to this group, send email to rubyonra...@googlegroups.com.
To unsubscribe from this group, send email to rubyonrails-co...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
Try this:
Project.joins(:services).where(:services => { :id => [1,2] }).group(:id).having("count(*) = 2").all
This produces to me:
"SELECT `projects`.* FROM `projects` INNER JOIN `services` ON `services`.`project_id` = `projects`.`id` WHERE `services`.`id` IN (1, 2) GROUP BY id HAVING count(*) = 2"
Which returns me only the projects who are associated to both services 1 and 2.
On Aug 11, 2012, at 6:23 PM, Rafael Almeida wrote:
> On Friday, August 10, 2012 5:50:58 PM UTC-3, EMoreth wrote:
> Try this:
>
> Project.joins(:services).where(:services => { :id => [1,2] }).group(:id).having("count(*) = 2").all
>
> This produces to me:
>
> "SELECT `projects`.* FROM `projects` INNER JOIN `services` ON `services`.`project_id` = `projects`.`id` WHERE `services`.`id` IN (1, 2) GROUP BY id HAVING count(*) = 2"
>
> Which returns me only the projects who are associated to both services 1 and 2.
>
> Indeed that does the trick. Nice thinking. It's probably even better than the intersection approach from SQL point of view.
>
> Anyway, the reason we don't have & and | operators in activerecord is that it's believed that there's always a better way to write a query not using them?
I'd say it's more that it's phenomenally difficult to come up with a *generic* method that will transform (for instance) your two queries:
Person.joins(:services).where('services.type' => 1)
Person.joins(:services).where('services.type' => 2)
into the final query. Note that the suggestion above is only correct if you never have Project with two links to the same service. Based on the what you've described about your domain, this is probably a sensible assumption - but the general case wouldn't necessarily be able to assume that.