Subtracting two queries from each other in rails - ruby-on-rails

I'm new to rails, and even ruby, so I'm having some trouble figuring this out.
I want to find the difference between two queries. This particular query should return a single record, since I've set it up such that Recipe is missing one of the IDs from recipes.
Current code:
q = Recipe.all - Recipe.where(recipe_id: recipes)
Where recipes is an array of IDs.
From my limited understanding of the language, this would work if both Recipe.all and Recipe.where both returned arrays.
I've spent some time searching the web, with nothing coming up to aid me.
Other things I've tried:
q = [Recipe.all] - [Recipe.where(recipe_id: recipes)]
q = Recipe.where.not(recipe_id: recipes) # Wouldn't work because the array is the one with the extra id
Though neither proved helpful.

Try this:
q = Recipe.where('recipe_id NOT IN (?)', recipes)

Turns out I was asking the wrong question.
Since the array of IDs is the one with extra elements, not the database query, I should have been comparing the difference of it to the query.
My answer is as follows:
q = recipes - Recipe.where(recipe_id: recipes).ids
Which returns the missing IDs.

If you are using Rails 4, you can use the not query method
q = Recipe.where.not(id: recipes)
this will generator following query:
SELECT "recipes".* FROM "recipes" WHERE ("recipes"."id" NOT IN (12, 8, 11, 5, 6, 7))

Related

How to query to return the most common foreign key in a join table with rails

I have 3 models. Project, ProjectMaterial, and Material
A Project has_many ProjectMaterials and many Materials through ProjectMaterials.
This is bidirectional, with ProjectMaterial acting as a join table with user-submittable attributes.
I'd like to query the ProjectMaterial model to find the most frequent value of material_id. This way I can use it to find the most frequently used material.
Any help with a query would be greatly appreciated. I'm stuck. Thanks in advance!
You can chain group, count and sort methods on your ActiveRecord query like this:
ProjectMaterial.group(:material_id).count.values.sort.last
The first part ProjectMaterial.group(:material_id).count gives you the hash of each {material_id0 => rows_count0, material_id1 => rows_count1, ...}. Then, you can just get the values of the hash in an array, sort it and get the last item.
One way could be pluck ids to get the array, then count the most frequent.
ids = ProjectMaterial.pluck[:material_id]
For example: Ruby: How to find item in array which has the most occurrences?
Or better, by query to get a hash with counts:
counts = ProjectMaterial.group(:material_id).count
Once you know that you get a hash, you can sort by any ruby method, picking the most frequent or the n most frequent. Example of sorting:
counts.sort_by { |_, v| v }

distinct for sorting with ransack

i was trying to sort values of a table with sort_link from Ransack. i found an example which is really helpful. but, i think i'm having problem with 'distinct'. i got this error 'ORDER-BY expressions must appear in SELECT list; DISTINCT'.
my code looks like this :
q =user.joins(:buyer).order('users.name')
ransack = params["filter"]
#search = q.search(ransack)
#users = #search.result(:distinct=>true)
do i forget something? thanks in advance!
As per this issue you might be able to solve this with an ActiveRecord joins query or select query to add the columns needed, for example:
q = user.order('users.name')
ransack = params["filter"]
#search = q.search(ransack).
result(:distinct=>true).
joins(:buyer).
includes(:buyer)
#users = #search.all
You have distinct as true. Ransack called the distinct value in the wrong manner with Postgresql, thefore you getting this error. If you use another database, you mostlikely would not.
So, if you make distinct false, you will not get this error. If you want to know why you need distinct, check out:
http://www.w3schools.com/sql/sql_distinct.asp
I am trying to find a way to include distinct if I need it. when I find out, I will edit this answer.

Ruby On Rails - Geocoder - Near with condition

I'm using GeoCoder in my application. Now I need to search for objects in my database which are close to a position OR have specific attribute set. I would like to perform this action in one database query, because the database is realy huge.
I would like to have something like
Spot.near([lat,long],distance).where("visited = ?",true).
The distance and the visited attribute should be combined with an OR, not with an AND.
Does anyone have an idea how to do this?
Thank you!
Based off of this answer, you should be able to do something like:
near = Spot.near([lat, long], distance)
visited = Spot.where(visited: true)
near = near.where_values.reduce(:and)
visited = visited.where_values.reduce(:and)
Spot.where(near.or(visited))
I'm in the process of upgrading a Rails application from Rails 4 to Rails 7 and ran into this problem. While I have no doubt Luke's suggestion worked in earlier versions, it doesn't work in Rails 7 (I'm currently running activerecord-7.0.3.1.
In my particular case, I am using the geocoder near() method to return results that are within a 20 mile radius of the query, but I also wanted to use OR conditions to return results where the query was similar to the text values in either the name or location columns from the items table in an attempt to return relevant items that haven't been assigned latitude and longitude values.
In Rails 4, my solution was:
select("items.*").near(q, 20, select: :geo_only).tap do |near_query|
near_query.where_values.last << sanitize_sql([" OR items.location LIKE ? OR items.name LIKE ?", "%#{q}%", "%#{q}%"])
end
In Rails/ActiveRecord 7, the where_values() method no longer exists. Searching for an alternate solution led me to this post. I wound up spending a fair amount of time perusing the latest ActiveRecord and Arel code for a solution. Here's what I came up with,
Rails 7 solution:
t = Item.arel_table
arel_geo_conditions = Item.near(q, 20).where_clause.ast # ast: Abstract Syntax Tree
Item.where(arel_geo_conditions.or(t[:location].matches("%#{q}%").or(t[:name].matches("%#{q}%"))))

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

Get all ids from a collection

I got my collection items like this :
hotels = Hotel.where('selection = ?', 1).limit(4)
How can I get all ids of this items without a loop? Can i use something like :
hotels.ids ?
Thank you
What about trying hotels.map(&:id) or hotels.map{|h| h.id }?
They both mean the same thing to Ruby, the first one is nicer to accustomed ruby-ists usually, whilst the second one is easier to understand for beginners.
If you only need an array with all the ids you should use pluck as it makes the right query and you don't have to use any ruby. Besides it won't have to instantiate a Hotel object for each record returned from the DB. (way faster).
Hotel.where(selection: 1).pluck(:id)
# SELECT hotels.id FROM hotels WHERE hotels.selection = 1
# => [2, 3]
If you are using Rails > 4, you can use the ids method:
Person.ids # SELECT people.id from people
More info: http://apidock.com/rails/ActiveRecord/Calculations/ids
You can also pull just the id's.
hotels.select(:id).where(selection: 1)

Resources