Given a query how to reduce the number of items - ruby-on-rails

I'm trying to do the following in rails 3:
#groups_active = Group.active_groups(current_user)
active_groups is a scope. This query works fine. I then want to do the following:
if #groups_active.count > 9
#groups_active[0..10]
end
Meaning if there are more than 10 items in the #groups_active, take just the TOP 10, which thanks to the scope ordering are the most active.
Suggestions? Thanks

I'm not sure what your problem is. You can limit the number of results from a query with Model.your_scope.limit(10), and if it is a query that doesn't work with a SQL LIMIT then you can use Model.your_scope.first(10). That's an Array#first, which accepts a fixnum argument to be used as expected…

#groups_active = Group.active_groups(current_user).limit(10)
or you could add the .limit(10) part to your scope.
Edited
I would go with one limit(10) request and one count. It could be more effective then retrieving 20, 50, or more records and using only the first 10 of them.
But still, it requires testing and benchmarking.

Related

Combining queries into an ActiveRecord_AssociationRelation

Hi I'm working on a project and I need to take result of two database queries and combine them into one ActiveRecord_AssociationRelation, at the moment I have:
results.where(pos_or_neg: "neg").order("value DESC") + (results.where(pos_or_neg: "pos").order("value ASC"))
However this returns an array which doesn't work as I need to do more processing afterwards. I've tried:
results.where(pos_or_neg: "neg").order("value DESC").merge(results.where(pos_or_neg: "pos").order("value ASC"))
but this only seems to return the half of the results.
Thanks
results.order("pos_or_neg ASC,case when pos_or_neg="neg" then value else -1*value end DESC")
I believe using merge is the equivalent of an AND query in SQL. What you are looking for is an OR query.
Since Rails 5 this is one of the Active Record query methods that you can use!
http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-or
Try to replace your .merge with .or and see if that works better

Range of IDs via ActiveRecord

I understand that I can use People.first(100) to retrieve the first 100 records, same goes for People.last(100).
What I don`t know, is how do I retrieve all objects in the range of 200-400, when the total number is lets say a 1000 records ?
What you need is limit and offset - read this for more info.
Example:
People.limit(200).offset(200)
The above code takes 200 records starting from 201st record - that means it would be records 201-400.
Are you searching on a specific field, your title suggests you're searching on id?
People.where('id BETWEEN ? AND ?', 200, 400)
or...
People.where(id: 200..400)
If you're not searching on a particular field, you would want to use Big_Bird's limit and offset methods.

How to make Active Record join return unique objects?

I have a simple query need: Find a list of users who made an order since Jan 1, 2013.
In SQL, it's a very simple query.
But I'm using Rails and Active Record.
So I wrote: User.joins(:orders).where("orders.created_at >= '2013-01-01 00:00:00'")
In our database, we have 100 orders made since 01/01/2013 by 75 users. (Some users made more than one order apparently.)
However, the expression above returns 100 users. (There must be duplicates.)
I tried User.joins(:orders).where("orders.created_at >= '2013-01-01 00:00:00'").uniq
That doesn't work either.
How can I get the 75 users who've made an order since 01/01/2013?
#dbjohn has the right idea, but I assume you want to avoid creating extra objects. Here's a slight variant on his solution, letting the database do the uniq-ing for you:
date = "2013-01-01 00:00:00"
User.joins(:orders).where("orders.created_at >= ?", date).distinct
Note that you can rearrange the order of methods to fit whatever you think is most semantic, and ActiveRecord will write the same SQL for you.
User.joins(:orders).
where("orders.created_at >= '2013-01-01 00:00:00'").
group('users.id')
group method will chain to the query and give you a list of unique records.
You can write nested query like this:
User.where(id: User.joins(:orders).where("orders.created_at >= '2013-01-01 00:00:00'").ids)
Rails has added uniq since version 3.2.1
so now you can use uniq
http://apidock.com/rails/ActiveRecord/QueryMethods/uniq

Return every nth row from database using ActiveRecord in rails

Ruby 1.9.2 / rails 3.1 / deploy onto heroku --> posgresql
Hi, Once a number of rows relating to an object goes over a certain amount, I wish to pull back every nth row instead. It's simply because the rows are used (in part) to display data for graphing, so once the number of rows returned goes above say 20, it's good to return every second one, and so forth.
This question seemed to point in the right direction:
ActiveRecord Find - Skipping Records or Getting Every Nth Record
Doing a mod on row number makes sense, but using basically:
#widgetstats = self.widgetstats.find(:all,:conditions => 'MOD(ROW_NUMBER(),3) = 0 ')
doesn't work, it returns an error:
PGError: ERROR: window function call requires an OVER clause
And any attempt to solve that with e.g. basing my OVER clause syntax on things I see in the answer on this question:
Row numbering in PostgreSQL
ends in syntax errors and I can't get a result.
Am I missing a more obvious way of efficiently returning every nth task or if I'm on the right track any pointers on the way to go? Obviously returning all the data and fixing it in rails afterwards is possible, but terribly inefficient.
Thank you!
I think you are looking for a query like this one:
SELECT * FROM (SELECT widgetstats.*, row_number() OVER () AS rownum FROM widgetstats ORDER BY id) stats WHERE mod(rownum,3) = 0
This is difficult to build using ActiveRecord, so you might be forced to do something like:
#widgetstats = self.widgetstats.find_by_sql(
%{
SELECT * FROM
(
SELECT widgetstats.*, row_number() OVER () AS rownum FROM widgetstats ORDER BY id
) AS stats
WHERE mod(rownum,3) = 0
}
)
You'll obviously want to change the ordering used and add any WHERE clauses or other modifications to suit your needs.
Were I to solve this, I would either just write the SQL myself, like the SQL that you linked to. You can do this with
my_model.connection.execute('...')
or just get the id numbers and find by id
ids = (1..30).step(2)
my_model.where(id => ids)

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