I have 3 tables PostText, PostImage and PostVideo.
Now I am combining data from all the above three table into a single array called userposts.
Now from userposts I want to access only 10 records starting with offset 15.
How can I do that?
I tried out userposts.first(10). It gives me first 10 records but I want 10 records starting from offset-15.
thanks in advance.
userposts.drop(15).first(10) will help you
You should use ary[start, length] → new_ary or nil method.
..returns a subarray starting at the start index and continuing for length elements,
userposts[10, 15]
Related
I have a query that loads thousands of objects and I want to tame it by using find_in_batches:
Car.includes(:member).where(:engine => "123").find_in_batches(batch_size: 500) ...
According to the docs, I can't have a custom sorting order: http://www.rubydoc.info/docs/rails/4.0.0/ActiveRecord/Batches:find_in_batches
However, I need a custom sort order of created_at DESC. Is there another method to run this query in chunks like it does in find_in_batches so that not so many objects live on the heap at once?
Hm I've been thinking about a solution for this (I'm the person who asked the question). It makes sense that find_in_batches doesn't allow you to have a custom order because lets say you sort by created_at DESC and specify a batch_size of 500. The first loop goes from 1-500, the second loop goes from 501-1000, etc. What if before the 2nd loop occurs, someone inserts a new record into the table? That would be put onto the top of the query results and your results would be shifted 1 to the left and your 2nd loop would have a repeat.
You could argue though that created_at ASC would be safe then, but it's not guaranteed if your app specifies a created_at value.
UPDATE:
I wrote a gem for this problem: https://github.com/EdmundMai/batched_query
Since using it, the average memory of my application has HALVED. I highly suggest anyone having similar issues to check it out! And contribute if you want!
The slower manual way to do this, is to do something like this:
count = Cars.includes(:member).where(:engine => "123").count
count = count/500
count += 1 if count%500 > 0
last_id = 0
while count > 0
ids = Car.includes(:member).where("engine = "123" and id > ?", last_id).order(created_at: :desc).limit(500).ids #which plucks just the ids`
cars = Cars.find(ids)
#cars.each or #cars.update_all
#do your updating
last_id = ids.last
count -= 1
end
Can you imagine how find_in_batches with sorting will works on 1M rows or more? It will sort all rows every batch.
So, I think will be better to decrease number of sort calls. For example for batch size equal to 500 you can load IDs only (include sorting) for N * 500 rows and after it just load batch of objects by these IDs. So, such way should decrease have queries with sorting to DB in N times.
No matter how I swing it, I need some kind of function to find the index of a item in an array supplied as a parameter.
I am trying to simply update items in a collection based on the index of one of their properties in an array, and have been poring through Cypher docs for nearly 2 hours...
It would also be acceptable to order the items by that array, and then run a foreach on the ordered list...
Following #stefan-armbruster answer and great blog post, a slow but simple index_of can be done with:
reduce(x=[-1,0], i IN [1,2,7,5,21,5,1,435] |
CASE WHEN i = 21 THEN [x[1], x[1]+1] ELSE [x[0], x[1]+1] END
)[0]
Here reduce function works with a two elements array: the position and the current index. If an element in your array matches the given condition, the first element of the reduced array will be replaced with the current index.
I put an example on neo4j console http://console.neo4j.org/?id=34byv
I've blogged about that recently. You can use the reduce function with an three element array as state variable containing
the index of the highest occupation so far
the current index (aka iteration number)
the value of highest occupation so far
As an example to find the index of max element in an array:
RETURN reduce(x=[0,0,0], i IN [1,2,2,5,2,1] |
CASE WHEN i>x[2] THEN [x[1],x[1]+1,o] ELSE [x[0], x[1]+1,x[2]] END
)[0]
I have an active record of 5 objects as follows
#top_sold = Photo.where(photographer_id: #photog).order('qty_sold DESC').first(5)
I want to know the sum of qty_sold for all 5 photos
This isnt working
#top_sold.sum(:qty_sold)
Much thanks in adcance
.first returns Array, use limit instead (which returns ActiveRecord::Relation).
#top_sold = Photo.where(photographer_id: #photog).order('qty_sold DESC').limit(5)
for Array you can do
#top_sold.map(:qty_sold).inject(:+)
Have you tried appending sum to your query?
#top_sold = Photo.where(photographer_id: #photog)
.order('qty_sold DESC').first(5).sum('qty_old')
If you need the original result set, then #Nithin answer is what you want to do.
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.
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.