How do I extract a field from an array of my models in order to form a single query? - ruby-on-rails

I’m using Rails 4.2.7. I have an array of my model objects and currently I’m iterating through that array to find matching entries in the database based on a field my each object …
my_object_times.each_with_index do |my_object_time, index|
found_my_object_time = MyObjectTime.find_by_my_object_id_and_overall_rank(my_object_id, my_object_time.overall_rank)
My question is, how can I rewrite the above to run one query instead of N queries, if N is the size of the array. What I wanted was to force my underlying database (PostGres 9.5) to do a “IF VALUE IN (…)” type of query but I’m not sure how to extract all the attributes from my array and then pass them in appropriately to a query.

I would do something like this:
found_my_object_times = MyObjectTime.where(
object_id: my_object_id,
overall_rank: my_object_times.map(&:overall_rank)
)

Related

Active Record Array array query - to check records that are present in an array

I have an Objective model which has an attribute called as labels whose values are array data type. I need to query all the Objectives whose labels attribute has values that are present in some particular array.
For Example:
I have an array
a = ["textile", "blazer"]
the Objective.labels may have values as ["textile, "ramen"]
I need to return all objectives that might have either "textile" or "blazer" as one of their labels array values
I tried the following:
Objective.where("labels #> ARRAY[?]::varchar[]", ["textile"])
This returns some records.Now when I try
Objective.where("labels #> ARRAY[?]::varchar[]", ["textile", "Blazer"])
I expect it to return all Objectives which contains at-least one of the labels array value as textile or blazer.
However, it returns an empty array. Any Solutions?
Try && overlap operator.
overlap (have elements in common)
Objective.where("labels && ARRAY[?]::varchar[]", ["textile", "Blazer"])
If you have many rows, a GIN index can speed it up.

Updating the column of object in rails object by its position in the array

I have an array of objects in Rails for some table. I want to update its order field by the position of that object in the array with a single Active Record Query. How can I do that?
I have tried the update_all.(:"order" => ?) but couldn't get the object which is updating in update_all.
Suppose #user (only a reference you can use your corresponding object) is the array of objects (Activerecord) , then to update order field of all users in the array, you would have to run the following query
#user.update_all(order_field: value)
Suppose you have an array of posts, then you can do something like the following
posts.each_with_index do |post, index|
post.update_attributes order: index
end
This will execute a single query for each post. If you want a single query to update all the posts in the array, that is a lot harder to achieve. Options I can think of:
bulk updating
using a stored procedure

In Rails 3.2, how to "pluck_in_batches" for a very large table

I have a massive table Foo from which I need to pluck all values in a certain field, Foo.who.
The array has millions of rows, but only a few thousand different values in the who column.
If the table was smaller of course I'd simply use Foo.pluck(:who)
If I use Foo.find_in_batches do |a_batch| each set is an Array of Foo records, rather than an activerecord collection of Foo records, so I cannot use .pluck() and AFAIK the only way to extract the who column is via something like .map(&:who) that iterates over the array.
Is there a way to pluck the who column from Foo in batches that does not require then iterating over each element of each batch to extract the who column?
In Rails 5 you can use:
Foo.in_batches do |relation|
values = relation.pluck(:id, :name, description)
...
end
Upd: for prevent memory leaks use:
Foo.uncached do
Foo.in_batches do |relation|
values = relation.pluck(:id, :name, description)
...
end
end
Here's a method to get the ids that were retrieved by the in_batches method itself, without need to run another query yourself.
in_batches already runs pluck(:id) under the hood (when load param is false which is the default) and yield the relation object. This relation object is created with where(id: ids_from_pluck).
Is it possible to get the list of ids directly from the relation object via where_values_hash method, without the need to run another query in DB. For example:
Foo.in_batches do |relation|
ids = relation.where_values_hash['id']
end
This should work on both Rails 5.x and 6.x, but it relies on implementation detail of in_batches so it is not guaranteed to work in future.
Try this:
Foo.select(:id, :who).find_in_batches do |a_batch|
...
end

rails combine parameters in controller

Hopefully this is a little clearer. I'm sorry but I'm very new to coding in general. I have multiple tables that I have to query in succession in order to get to the correct array that I need. The following logic for the query is as follows:
this gives me an array based upon the store :id
store = Stores.find(params[:id])
this gives me another array based upon the param .location found in the table store where that value equals the row ID in the table Departments
department = Departments.find(store.location)
I need to preform one last query but in order to do so I need to figure out which day of the meeting is needed. In order to do this I have to create the parameter day_of_meeting found in the table Stores. I try to call it from the array above and create a new variable. In the Table Departments, I there are params such as day_1, day_2 and so on. I need to be able to call something like department.day_1 or department.day_2. Thus, I'm trying to actually create the variable by join the words "department.day_" to the variable store.day_of_meeting which would equal some integer, creating department.day_1...
which_day = ["department.day_", store.day_of_meeting].join("")
This query finds uses the value found from the variable department.day_1 to query table Meeting to find the values in the corresponding row.
meeting = Meeting.find(which_day)
Does this make my problem any clearer to understand?
findmethod can only accept parameters like Meeting.find(1) or Meeting.find("1-xx").
so, what you need is Meeting.find(department.send("day_" + store.day_of_meeting.to_s))
Hope to help!

Modifying the returned value of find_by_sql

So I am pulling my hair over this issue / gotcha. Basically I used find_by_sql to fetch data from my database. I did this because the query has lots of columns and table joins and I think using ActiveRecord and associations will slow it down.
I managed to pull the data and now I wanted to modify returned values. I did this by looping through the result ,for example.
a = Project.find_by_sql("SELECT mycolumn, mycolumn2 FROM my_table").each do |project|
project['mycolumn'] = project['mycolumn'].split('_').first
end
What I found out is that project['mycolumn'] was not changed at all.
So my question:
Does find_by_sql return an array Hashes?
Is it possible to modify the value of one of the attributes of hash as stated above?
Here is the code : http://pastie.org/4213454 . If you can have a look at summarize_roles2() that's where the action is taking place.
Thank you. Im using Rails 2.1.1 and Ruby 1.8. I can't really upgrade because of legacy codes.
Just change the method above to access the values, print value of project and you can clearly check the object property.
The results will be returned as an array with columns requested encapsulated as attributes of the model you call this method from.If you call Product.find_by_sql then the results will be returned in a Product object with the attributes you specified in the SQL query.
If you call a complicated SQL query which spans multiple tables the columns specified by the SELECT will be attributes of the model, whether or not they are columns of the corresponding table.
Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
> [#<Post:0x36bff9c #attributes={"title"=>"Ruby Meetup", "first_name"=>"Quentin"}>, ...]
Source: http://api.rubyonrails.org/v2.3.8/
Have you tried
a = Project.find_by_sql("SELECT mycolumn, mycolumn2 FROM my_table").each do |project|
project['mycolumn'] = project['mycolumn'].split('_').first
project.save
end

Resources