How do I combine results from two queries on the same model?

前端 未结 4 1988
南方客
南方客 2021-02-15 13:56

I need to return exactly ten records for use in a view. I have a highly restrictive query I\'d like to use, but I want a less restrictive query in place to fill in the results i

相关标签:
4条回答
  • 2021-02-15 14:36

    I think you can do all of this in one query:

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

    I may have the sort order wrong on the listed column, but in essence this should work. You'll get any listed items first, sorted by created_at DESC, then non-listed items.

    0 讨论(0)
  • 2021-02-15 14:39

    All you need to do is sum the queries:

    result1 = Model.where(condition)
    result2 = Model.where(another_condition)
    
    # your final result
    result = result1 + result2
    
    0 讨论(0)
  • 2021-02-15 14:48

    If you want an ActiveRecord::Relation object instead of an Array, you can use:

    • ActiveRecordUnion gem.

      Install gem: gem install active_record_union and use:

      def self.current
        Article.rescue_articles.union(Article.listed_articles).limit(10)
      end
      
    • UnionScope module.

      Create module 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
      

      Then call it in your Article model.

      class Article < ActiveRecord::Base
        include ActiveRecord::UnionScope
        ...
        def self.current
          union_scope(Article.rescue_articles, Article.listed_articles).limit(10)
        end
        ...
      end
      
    0 讨论(0)
  • 2021-02-15 14:51

    with your initial code:

    You can join two arrays using + then get first 10 results:

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

    I suppose a really dirty way of doing it would be:

      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
    
    0 讨论(0)
提交回复
热议问题