0

I have a long array of Photo model objects, and I want to sort them by created_at, newest first, then get a new array with the first 21 photos.

My problem is that the final array is not ordered properly.

Here is my code:

@recent_photos = photos.sort_by(&:created_at).reverse.first(21)

when I print out @recent_photos the created_at values are ordered like this:

1458948707
1458943713
1458947042
1458945171
...

What is the correct way to sort objects?

UPDATE:

here's how the initial list is compiled:

photos = @user.photos
@following = @user.following
@following.each do |f|
  photos += f.photos if f.id != @user.id
end
@user.memberships.each do |group|
  photos += group.photos
end

SOLUTION:

problem was with the question - I wanted to sort by timestamp not created_at, and those were timestamp values in the output

5
  • The sorting should work fine from what I can see, what class type is your created_at? Commented Mar 26, 2016 at 0:28
  • idk, it was auto generated by Rails, but if its a string that might be the problem? Commented Mar 26, 2016 at 0:29
  • Could you run photos.map(&:created_at).first(21) and paste it? Your sorting should definitely be in the correct order unless I'm missing something. Commented Mar 26, 2016 at 0:32
  • Ran that and they are definitely in order in that output Commented Mar 26, 2016 at 0:37
  • You'll need to add a bit more information, what does 'photos' look like? is it an array of active record objects? or hashes? A small mock model should help. What is your expected output? Commented Mar 26, 2016 at 0:45

2 Answers 2

4

You can crunch it all down into a single query:

@recent_photos = Photo.where(
  user_id: @user.following_ids
).order('created_at DESC').limit(21)

You really do not want to be doing N queries for each of these as it will get slower and slower as a person has more people they're following. If they follow 10,000 people that's a ridiculous number of queries.

If you add a :through definition to your model you may even be able to query the photos directly:

 has_many :follower_photos,
   class_name: 'Photo',
   through: :followers

Whatever your constraints are, boil them down to something you can query in one shot whenever possible. If that's not practical, get it down to a predictable number of queries, never N.

Sign up to request clarification or add additional context in comments.

12 Comments

but how would I get all followers photos, groups photos, and personal photos with the same query? the example is just for followers
Ideally you have a singular table that represents a person or a group, or you create stub "person" records for groups to work around this. You can also use Single Table Inheritance (STI) to combine person and group into the same table, or use a polymorphic table to join them but that can be considerably more messy. Ideally the STI approach is the easiest to effect. If you do have two different relations, you can join them with the .or(...) method to add another condition set.
For performance reasons I tend to avoid or situations whenever possible. MySQL has to do a lot of work to combine two result sets and sort them if you use that. Using a single table is super efficient if you can have an index on the WHERE and ORDER BY criteria.
yea I'm not sure that I can avoid an or, b/c it shouldn't return the person's photos from a group that they've left, and there are other nuances.. but anyway, speed of implementation is more important that the speed of the function rn, so could you help me find a way to sort the array I already have?
Ah, that would do it. Always give a little attention to performance considerations. You don't want to paint yourself into a corner because of a bad schema design.
|
3

Try:

@recent_photos = Photo.order('created_at desc').first(21)

2 Comments

I can't query Photo directly, b/c the initial photo list is a select group of objects, not query-able with SQL
ah--I see that now...could you show how you're building that array of objects?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.