Как объединить результаты двух запросов в одной модели? - PullRequest
7 голосов
/ 24 марта 2011

Мне нужно вернуть ровно десять записей для использования в представлении. У меня очень строгий запрос, который я хотел бы использовать, но я хочу использовать менее строгий запрос для заполнения результатов в случае, если первый запрос не даст десять результатов.

Просто поиграть несколько минут, и это то, что я придумал, но это не работает. Я думаю, что это не работает, потому что слияние предназначено для объединения запросов в разных моделях, но я могу ошибаться.

class Article < ActiveRecord::Base
...
  def self.listed_articles
    Article.published.order('created_at DESC').limit(25).where('listed = ?', true)
  end

  def self.rescue_articles
    Article.published.order('created_at DESC').where('listed != ?', true).limit(10)
  end

  def self.current
    Article.rescue_articles.merge(Article.listed_articles).limit(10)
  end
...
end

При просмотре в консоли это накладывает ограничения в перечисленных списках на запрос в rescue_articles, показывая что-то вроде:

Article Load (0.2ms)  SELECT `articles`.* FROM `articles` WHERE (published = 1) AND (listed = 1) AND (listed != 1) ORDER BY created_at DESC LIMIT 4
Article Load (0.2ms)  SELECT `articles`.* FROM `articles` WHERE (published = 1) AND (listed = 1) AND (listed != 1) ORDER BY created_at DESC LIMIT 6 OFFSET 4

Я уверен, что есть какой-то смехотворно простой метод, который мне не хватает в документации, но я еще не нашел его.

EDIT: То, что я хочу сделать, это вернуть все статьи, где перечислены, верно из двадцати пяти самых последних статей. Если это не даст мне десять статей, я хотел бы добавить достаточное количество статей из самых последних статей, где перечисленные не соответствуют действительности, чтобы получить мои полные десять статей.

РЕДАКТИРОВАТЬ # 2: Другими словами, метод слияния, кажется, объединяет запросы в один длинный запрос вместо слияния результатов. Мне нужны первые десять результатов двух запросов (с указанием приоритетов в перечисленных статьях), а не один длинный запрос.

Ответы [ 4 ]

10 голосов
/ 24 марта 2011

с вашим исходным кодом:

Вы можете объединить два массива, используя +, а затем получить первые 10 результатов:

  def self.current
    (Article.listed_articles  +  Article.rescue_articles)[0..9]
  end

Полагаю, очень грязный способ сделать это будет:*

  def self.current
      oldest_accepted = Article.published.order('created_at DESC').limit(25).last
      Artcile.published.where(['created_at > ?', oldest_accepted.created_at]).order('listed DESC').limit(10)
  end
3 голосов
/ 15 апреля 2018

Если вам нужен объект ActiveRecord::Relation вместо массива, вы можете использовать:

  • ActiveRecordUnion gem .

    Установить гем:gem install active_record_union и используйте:

    def self.current
      Article.rescue_articles.union(Article.listed_articles).limit(10)
    end
    
  • Модуль UnionScope .

    Создание модуля UnionScope (lib / active_record / union_scope.rb).

    module ActiveRecord::UnionScope
      def self.included(base)
        base.send :extend, ClassMethods
      end
    
      module ClassMethods
        def union_scope(*scopes)
          id_column = "#{table_name}.id"
           if (sub_query = scopes.reject { |sc| sc.count == 0 }.map { |s|   "(#{s.select(id_column).to_sql})" }.join(" UNION ")).present?
            where "#{id_column} IN (#{sub_query})"
          else
            none
          end
        end
      end
    end
    

    Затем назовите это в вашей модели артикула. ​​

    class Article < ActiveRecord::Base
      include ActiveRecord::UnionScope
      ...
      def self.current
        union_scope(Article.rescue_articles, Article.listed_articles).limit(10)
      end
      ...
    end
    
2 голосов
/ 26 апреля 2013

Все, что вам нужно сделать, это суммировать запросы:

result1 = Model.where(condition)
result2 = Model.where(another_condition)

# your final result
result = result1 + result2
0 голосов
/ 24 марта 2011

Я думаю, вы можете сделать все это одним запросом:

 Article.published.order('listed ASC, created_at DESC').limit(10)

Возможно, в указанном столбце неправильный порядок сортировки, но по сути это должно работать. Сначала вы получите все перечисленные элементы, отсортированные по созданному DESC, а затем не внесенные в список.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...