How to update collection data for collection of ids? - ruby-on-rails

I am getting collection of ids [1,2,3,4] in the params and I make a call to an API that will return the array for the corresponding ids. E.g. ["Apple","Orange","Mango"]. How can I update this in my database for the corresponding ids?
For example: the ids which are mentioned above are from my user table. ids = [1,2,3,4], which are primary keys in my user table.
From the API response I got an array of fruit_names for the correlated user_ids. E.g.: ids = [1,2,3,4] and fruit_names = ["a","b","c","d"], where the fruit_name column exists in my user table. How do I update fruit_name from the API response correlated ids in my user table?

You can use each_with_index in combination with update for this:
ids.each_with_index do |id, index|
User.update(id, :fruit_name, fruit_names[index])
end
The above code assumes:
ids = [1,2,3,4]
fruit_names = ["a","b","c","d"]
and that the indexes of those arrays match.
Note that this will execute a query for each item in your ids array. If your ids array is very big this is not going to perform well.

Hash[ids.zip fruit_names].each do |id, fruit|
User.update_all({:fruit_name => fruit}, {:id => id})
end
OR
User.where(:id => ids).each do |usr|
usr.update_attribute(:fruit_name, fruit_names[ids.index(usr.id)])
end

Related

How to merge a Redis hash and a Rails record?

For example, I have a shopping cart(redis hash) which contains a product id and a count:
{"165"=>"2", "166"=>"3"}
How do I find all products with these ids?
I think something like that:
1) Product.where(id: hash.keys) , but then I lose the count.
2) I can iterate the hash:
#products = []
hash.each do |id, count|
product = Product.find(id)
#products << product
end
But I don't know how to add count param in the product record and I think this approach is inefficient, because I'll get O(N) queries.
How to solve this problem?
You can get an array of arrays with two elements, where the first is the product and the second is the count:
Product.find(hash.keys).index_by(&:id).values_at(*hash.keys).zip(hash.values)
You can also add .to_h at the end if you want it to be a hash.
I would really not recommend this, but if you absolutely want the count to be added to the Products themselves, you could use the result of the above and eigenclasses:
result.map do |product, count|
product.define_singlethon_method(:count) { count }
product
end

Activerecord query with array in where clause

I have a location table in my rails app which has four columns :-
| Id | Longitude | Latitude | user_id
Now I have an array containing the list of user_ids. How can I write an active record query to select the last row of each user id. For example, if I have three user_ids in my array [1,2,3] I want the query to return just the last row corresponding to each user_id (lets assume entries for each user_id is present in the table) from the table.
So, far I am able to get all the rows corresponding to all the user_ids using this following query:
#ids = [1,2,3]
#locations = Location.where(user_id: ids)
How can I modify this activerecord query so that it returns only the last row corresponding to each user_id
Assuming you have a User model that has many locations, you could start from the user model and use the association to get to your last location for each user.
User.where(:id => #ids).includes(:locations).collect { |u| u.locations.last }
User.where(:id => #ids) returns your collection of user objects.
includes(:locations) eager loads the associated locations, so we don't run into an n+1 problem.
collect { |u| u.locations.last } maps the last associated location into an array
You can also try this:
#ids = [1,2,3]
#locations = #ids.map {|id| [Location.where(user_id: id).last.location,User.find(id).name]}
#This would give you something like this: [["US",XYZ],["IND","ABC"]]

Rails order hash by values and array

I had array of users, and array of they id's. I'm need create hash with {name => id}, but with order of id's array. As example, when i wrote:
keys = [5, 3, 2, 4, 1]
users = User.all.where(id: keys).pluck(:name, :id).to_h
It's return me {"User_1"=>2, "User_2"=>3, "User_3"=>4, "User_4"=>5, "User_0"=>1}
But i'm need to get such thing:
{"User_4"=>5, "User_2"=>3, "User_1"=>2, "User_3"=>4, "User_0"=>1}
Is there opportunity to had such hash on where operation?
The array of users that you get from your database is ordered by the updated_at column. Try this:
users = User.where(id: keys).order(id: :desc).pluck(:name, :id).to_h

Iterating through an activerecord::relation array

How can I iterate through an array of Activerecord::Relation objects? For instance, let's say I have a Comment class and a User class and I'd like to get all the comment contents from 3 specific users (assuming comments belong to users and user_id is the foreign key):
>> #males = Comment.where('user_id IN (?)', ["123","456","789"])
=> [...] #Array of comment Activerecord::Relation objects
Now I'd like to iterate through comments_from_males and collect all the content attribute contents for each comment in the array.
To clarify, the following works but only for the first male returned, but I need all the comments for all males:
>> #males.first.comments.map(&:content)
=> ["first comment", "second comment"]
comments = #males.map {|user| user.comments.map(&:content)}.flatten
Comment.where('user_id IN (?)', ["123","456","789"]).pluck(:content)
The method pluck
You can use
comments_from_males = #males.collect{|e| e.content if e.gender == "male"}.flatten
It will give you list of all comments from males. Check my db assumptions match.

Compare hash with column - Rails

I'm getting a hash from an API call that returns values like the following:
[{"name"=>"Abby Allen", "id"=>"123"}, {"name"=>"Barry Burner", "id"=>"234"}, {"name"=>"Cat Catrelli", "id"=>"345"}, {"name"=>"Darrell Dogooder", "id"=>"456"}, {"name"=>"Eva Ewing", "id"=>"567"}]
I'd like to compare the id's from this hash to the "apiid" column that I current have in my database (User model), and return all IDs that the hash and "apiid" column have in common.
i.e. my apiid column in my User model looks like this
apiid
001
123
125
333
345
I was trying it this way, but any suggestions can't get it to work. Eventually, the apiid column will be long, so I'm looking for the most efficient way as well.
User.find_each(:select => "apiid") do |user|
#friendscommon = #friends.select{|key, hash| hash["id"] == user }
end
where #friends is the hash above.
Any suggestions would be appreciated. Thank you!
You want to extract an array of all the ids in the array of hashes:
apiids = hash.map { |user| user["id"] }
This will cause apiids to be an array of the ids, ie:
apiids = ["123","234","345","456","567"]
And pass it into a query:
User.select(:apiid).where(:apiid => apiids)
Here, the where clause effectively sees:
where(:apiid => ["123","234","345","456","567"])
which translates to:
SELECT apiid FROM users WHERE (users.apiid IN ("123","234","345","456","567"))

Resources