Ruby on Rails - Selecting a range from a query - ruby-on-rails

I'm doing a query to get all the purchases from the db. For example
orders = PurchaseOrders.all
I in the same query, how can I select only the first hundred orders(1-100) or just the next 100(101-200) etc..?
Thank you

You can use limit and offset:
PurchaseOrders.limit(200).offset(100)
which meant start from 200 and take 100 records. More info here. Or with take:
PurchaseOrders.offset(100).take(400)
take 400 records starting from 100.

For the first 100 records;
orders = PurchaseOrders.first(100)
and last 100 records;
orders = PurchaseOrders.last(100)
or by IDs,
orders = PurchaseOrders.find([100, 201])

Related

any way to limit result by node

I have this query:
MATCH (user:Users)-[buy:Sales]->(item:Items)<-[buy2:Sales]- (user2:Users)-[buy_other:Sales]->(item2:Items)
where item.category = item2.category
return
user.mail, item2.id
the idea is to get items that the first user could be interested in that other user2 also bought, but i want to limit the results to max 2 item2 id per user
I know i can limit results in general, with limit 10 for example, but that means that those 10 results could all be for the same user.
Any help? thanks in advance
You can do it by inserting a COLLECTing and getting the first n items of it.
MATCH (user:Users)-[buy:Sales]->(item:Items)<-[buy2:Sales]- (user2:Users)-[buy_other:Sales]->(item2:Items)
WHERE item.category = item2.category
// this is where you collect and get some items of it
WITH user,COLLECT(item2)[0..2] AS item2s
UNWIND item2s AS item2
RETURN
user.mail, item2.id

Rails ActiveRecord: How to select the top X records for each day, for multiple days in a single query?

The model is Posts, and each post has upvotes:integer
Hundreds of posts are created each day, and I want to return a the top 10 upvoted posts from each day with a single query.
ordered chronologically
I want to return the results for the past year, and show the top 10 posts from each day in the same query.
the expected result should be:
top 10 posts from today, top 10 posts from yesterday ... top 10 posts from the beginning.
is there any way to do this query without doing a loop and individual query for each day?
Try this
Post.where("DATE(created_at) = ?", Date.today).order("upvotes DESC").limit(10)
Here Date.today take today's date, you can pass any date to get top 10 for that particular day.
The more precise query would be
Post.where("created_at = ?", Date.today.beginning_of_day)
.order("upvotes DESC").limit(10)
Well any of the above solutions will work perfectly well if you have upvotes column in your posts table, however, if you have it in a separate table, which you ideally should, you would need something like below for the same:
query = <<-QUERY
SELECT posts.*,
Count(upvotes.*) AS upvotes_count
FROM posts
LEFT JOIN upvotes
ON upvotes.post_id = posts.id
WHERE Date(posts.created_at) = #{Date.today}
GROUP BY posts.id
ORDER BY upvotes_count DESC
QUERY
ActiveRecord::Base.connection.execute(query).entries
This is with raw sql though. You can convert it to ActiveRecord if you need.

Only return one record per hour over a time period in Rails

I have written a Rails 4 app that accepts and plots sensor data. Sometimes there are 10 points per hour (but this number is not fixed). I'm plotting the data and doing a simple query of Points.all to get all the data points.
In order to reduce the query size, I would like to only return one record per hour. It doesn't matter which record is returned. The first record each hour using the created_at field would be fine.
How do I construct a query to do this?
You can get first one, but maybe average value is better. All you need to do is to group it by hour. I am not 100% about sqlite syntax but something in this sense:
connection.execute("SELECT AVG(READING_VALUE) FROM POINTS GROUP BY STRFTIME('%Y%m%d%H0', CREATED_AT)")
Inspired from this answer, here is an alternative which retrieves the latest record in that hour (if you don't want to average):
Point.from(
Point.select("max(unix_timestamp(created_at)) as max_timestamp")
.group("HOUR(created_at)") # subquery
)
.joins("INNER JOIN points ON subquery.max_timestamp = unix_timestamp(created_at)")
This will result in the following query:
SELECT `points`.*
FROM (
SELECT max(unix_timestamp(created_at)) as max_timestamp
FROM `points`
GROUP BY HOUR(created_at)
) subquery
INNER JOIN points ON subquery.max_timestamp = unix_timestamp(created_at)
You can also use MIN instead to get the first record of the hour, if you like, as well.

How to select data for defined page and total count of records?

I have a table with paginated data and this is the way I select data for each page:
#visitors = EventsVisitor
.select('visitors.*, events_visitors.checked_in, events_visitors.checkin_date, events_visitors.source, events_visitors.id AS ticket_id')
.joins(:visitor)
.order(order)
.where(:event_id => params[:event_id])
.where(filter_search)
.where(mode)
.limit(limit)
.offset(offset)
Also to build table pagination I need to know total count of records. Currently my solution for this is very rough:
total = EventsVisitor
.select('count(*) as count, events_visitors.*')
.joins(:visitor)
.order(order)
.where(:event_id => params[:event_id])
.where(filter_search)
.where(mode)
.first()
.count
So my question is as follows - What is the optimal ruby way to select limited data for the current page and total count of records?
I noticed that if I do #visitors.count - additional sql query will be generated:
SELECT COUNT(count_column) FROM (SELECT 1 AS count_column FROM `events_visitors` INNER JOIN `visitors` ON `visitors`.`id` = `events_visitors`.`visitor_id` WHERE `events_visitors`.`event_id` = 1 LIMIT 15 OFFSET 0) subquery_for_count
First of all, I do not understand what is the reason to send an additional query to get a count of data that we already have, I mean that after we got data from database in #visitors we can count it with ruby without need to send additional queries to DB.
Second - I thought that maybe there are some ways to use something like .total_count that will generate similar count(*) query but without that useless limit/offset?
you should except limit and offset
http://guides.rubyonrails.org/active_record_querying.html#except .
See how kaminari does it
https://github.com/kaminari/kaminari/blob/92052eedf047d65df71cc0021a9df9df1e2fc36e/lib/kaminari/models/active_record_relation_methods.rb#L11
So it might be something like
total = #visitors.except(:offset, :limit, :order).count

restricting rows on solr subquery/join

I want to implement a search on solr that takes the 500 bestselling products, and then does a search/filter on those 500 products only
In SQL, I would do something like this:
SELECT * FROM Product
WHERE ProductID IN (SELECT TOP 500 ProductID FROM Product ORDER BY Sales DESC)
AND Manufacturer = 'Apple'
I know I can do join/subqueries in solr, but I can't seem to work out how to sort and limit the rows of these subqueries before they are fed into the main query.
Is this possible in solr?
You probably wont need any Joins or Subqueries.
You would index the Products with the Sales information.
You just need to execute a Solr Query :-
q=manufacturer:apple&sort=sales desc&limit=500
OR
fq=manufacturer:apple&sort=sales desc&limit=500
This would search the manufacture field for apple, return the result set ordered by sales in the descending order and limit the rows to 500.
Fetching 500 would probably not be a good idea and you can always do pagination with rows and limit.
The limit of showing only 500 results can be handled at client side.

Resources