Reputation: 6589
I have a table, let's call it Widget.
I do some complex processing to get various type of Widgets. These end up in two different variables.
To keep things simple, let's say we have...
widgetsA = Widget.where("blah blah blah")
widgetsB = Widget.where("blah blah blah blah")
We can still perform ActiveRecord functions like .where on widgetsA
and widgetsB
.
Now, after retrieving the sets for A and B, I need to union them, and then perform additional ActiveRecord functions on them.
I want to do something like this...
widgetsAll = widgetsA | widgetsB
widgetsAll = widgetsAll.order("RANDOM()")
widgetsAll = widgetsAll.where(answers_count: 0).limit(10) + widgetsAll.where("answers_count > 0").limit(10)
This will take all the widgets (union) found in A & B, randomize them, and select 10 with answers and 10 without answers.
The problem is, I cannot user .order
and widgetsAll is no longer an ActiveRecord object, but it's an Array because of the widgetsAll = widgetsA | widgetsB
line. How do I either
A) Union/Intersect two ActiveRecord sets, into an ActiveRecord set
B) How can I order and perform a 'where' style query on an Array.
Either will solve the issue. I assume B is a bit better for performance, so I suppose that would be the better answer.
Any ideas?
Lastly, lets say the Widget table has columns id, name, description. In the end we want an ActiveRecord or Array (likely preferred) of everything.
EDIT: (Attempting to combine via SQL UNION... but not working)
w1 = Widget.where("id = 1 OR id = 2")
w2 = Widget.where("id = 2 OR id = 3")
w3 = Widget.from("(#{w1.to_sql} UNION #{w2.to_sql})")
PG::SyntaxError: ERROR: subquery in FROM must have an alias
LINE 1: SELECT "widgets".* FROM (SELECT "widgets".* FROM "widge...
Upvotes: 2
Views: 1870
Reputation: 106802
I see two options:
1) Do the union in SQL: Instead of widgetsA | widgetsB
that return an array you can do an union in the database, so that the result is still a relation object:
Widget.from("(#{widgetA.to_sql} UNION #{widgetB.to_sql}) AS widgets")
2) Use normal array methods. Your example:
widgetsAll = widgetsAll.order("RANDOM()")
widgetsAll = widgetsAll.where(answers_count: 0).limit(10) + widgetsAll.where("answers_count > 0").limit(10)
would translate to something like this:
widgetsAll = widgetsAll.shuffle
widgetsAll = widgetsAll.select { |answer| widget.answer_count == 0 }.take(10) +
widgetsAll.select { |answer| widget.answers_count > 0).take(10)
Read more about Ruby arrays.
Upvotes: 2
Reputation: 13057
One way would be to do as follows:
widgetsAllActual = Widget.where(id: widgetsAll)
This is creating a new Widget::ActiveRecord_Relation
collection containing all the elements in widgetsA
and widgetsB
, and allows for making further active record scoping.
Ref: https://stackoverflow.com/a/24448317/429758
Upvotes: -1
Reputation: 115511
Using the any_of gem you could do:
widgetsAll = Widget.where.any_of(widgetsA, widgetsB)
Upvotes: 1