Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Выборка случайных документов из коллекции MongoDB

Anna | 20.06.2014 | нет комментариев
Недавно я столкнулся с одной достаточно банальной задачей, где мне необходимо было случайным образом выбирать из базы посты, написанные пользователями сайта. План написан на Rails с применением MongoDB в качестве базы данных и джем mongoid для работы с ней. Не то что бы задача была трудной для выполнения, но в то же время, на изумление, нет безусловно простого решения на подобие sort_by_random либо как бы того. Под катом пару примеров как это дозволено решить.
Для начала давайте разглядим примитивный метод решения задачи. В монгоиде есть способ, тот, что разрешает пропустить несколько записей либо, другими словами, установить курсор для точки отсчета. Данный способ именуется skip и ему дозволено передать число записей, которые стоит пропустить. Если у нас есть коллекция с тремя записями, то Дабы получить вторую, дозволено сделать что-то подобно этогоPost.skip(1).first. Зная число документов в коллекции, мы можем сделать сдвиг на случайное число документов и начать читать оттуда:

proxy = Post.where(...)
skip = rand(proxy.count - COUNT_OF_POSTS_TO_SHOW)
@posts = proxy.skip(skip).limit(COUNT_OF_POSTS_TO_SHOW)

Если у вас не будет особых условий по которым вы делаете выборку, то код будет выглядеть проще. Традиционно, некоторые данные все таки будут присутствовать, такие как дата создания либо ранг. Данная выборка достаточно таки случайна, но не вовсе, так как мы выбираем случайным образом точку отсчета, а дальше все документы идут подряд. Допустимо, кому-то подойдет и данный вариант случайности, исключительно если необходимо предпочесть только одну запись. Но данный способ может быть безусловно неприемлемым в случаях, когда мы выбираем товары, показывая таким образом товары из идентичной категории либо с идентичной ценой (в зависимости от индексов коллекции)
Мое решение для приобретения безусловно случайных записей было немножко труднее, но давало больше правильные итоги. Для этого мне потребовалось добавить новое поле к коллекции из которой делалась выборка, я назвал его rand_order. В него мы записывали случайное число с плавающей точкой от 0 до 1. Особенно опрятный метод заполнения этого поля, это добавить before_save фильтр для модели, тот, что может выглядеть таким образом:

 def set_rand_order
    self.rand_order = (rand 0.0..1).round(15) unless rand_order
  end

Таким образом, всякий раз при сохранении объекта, мы проверяем заполнено ли значение для поля rand_order и заполняем его если оно пустое. Приобретение случайных записей сейчас будет протекать значительно проще:

Post.asc(:rand_order).limit(COUNT_OF_POSTS_TO_SHOW)

Стоит брать во внимание, что если вы применяете данный метод для теснее присутствующей коллекции, которая содержит документы, то для них необходимо сгенерировать случайные числа для поля rand_order. Это дозволено сделать в миграции и с учетом того, что мы сделали это в before_filter, вам довольно вызвать способ save для всякого из объектов:

Post.all.each{|p| p.save}

 

Источник: programmingmaster.ru

 

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB