#ruby-on-rails #ruby-on-rails-3 #activerecord #random #limit
#ruby-on-rails #ruby-on-rails-3 #activerecord #Случайный #ограничение
Вопрос:
Итак, в моем приложении есть фотографии, принадлежащие коллекциям. Я хочу иметь возможность показывать 13 фотографий из определенной коллекции на странице.
Я пробовал это:
c = Collection.first
@photos = c.photos.offset(rand(c.photos.count)).limit(13)
Это работает, вроде как. Проблема в том, что если в коллекции не намного больше 13 фотографий, то она не обязательно возвращает 13 фотографий. Мне нужно конкретно получить ровно 13 фотографий.
FWIW В случае моего приложения коллекция создается только администраторами / модниками, поэтому мы можем обеспечить, чтобы ни в одной коллекции не было меньше 13 фотографий. Что мне нужно, так это иметь возможность начать выбирать фотографии случайным образом, как только будет доступно более 13.
Как я мог это сделать?
Ответ №1:
Вы могли бы сначала выбрать 13 случайно связанных идентификаторов фотографий, а затем выполнить запрос к базе данных для их извлечения:
c = Collection.first
random_ids = c.photo_ids.sort_by { rand }.slice(0, 13)
@photos = Photo.where(:id => random_ids)
Комментарии:
1. В вашем комментарии сказано «до 13 фотографий», вернет ли это РОВНО 13 фотографий? Я не могу использовать его, если он возвращает меньше.
2. Ну, он не может вернуть 13 фотографий, если в коллекции меньше 13 идентификаторов photo_ids. В остальном, да, так и есть.
Ответ №2:
Просто отсортируйте их случайным образом в sql и возьмите первые 13. так что делайте:
c.photos.order("RAND()").limit(13)
Комментарии:
1. Работает ли это в SQLite и PostgreSQL? Я не очень хорошо разбираюсь в SQL, но в прошлом у меня были проблемы между моей средой разработки и производственной средой из-за различий в SQL.
2. Вы всегда можете попробовать и выяснить. Я почти уверен, что
RAND()
работает в большинстве реализаций SQL.3. Будьте осторожны, потому что это НЕВЕРОЯТНО неэффективно и на больших наборах данных займет гораздо больше времени, чем необходимо для выполнения.
4. POSTGRES и SQLite3 используют ‘RANDOM()’. Это зависит от базы данных.
5. Это, по-видимому, чрезвычайно медленно.
Ответ №3:
Вот быстрое решение.. в настоящее время использует его с более чем 1,5 миллионами записей и получает приличную производительность. Лучшим решением было бы кэшировать один или несколько наборов случайных записей, а затем обновлять их с помощью фонового рабочего с желаемым интервалом.
Созданный random_records_helper.rb
файл:
module RandomRecordsHelper
def random_user_ids(n)
user_ids = []
user_count = User.count
n.times{user_ids << rand(1..user_count)}
return user_ids
end
в контроллере:
@users = User.where(id: random_user_ids(10))