복붙노트

[RUBY-ON-RAILS] 액티브 쿼리 연합

RUBY-ON-RAILS

액티브 쿼리 연합

나는 레일의 쿼리 인터페이스에 루비 (적어도 나에게) 복잡한 쿼리의 몇 가지를 작성했습니다 :

watched_news_posts = Post.joins(:news => :watched).where(:watched => {:user_id => id})
watched_topic_posts = Post.joins(:post_topic_relationships => {:topic => :watched}).where(:watched => {:user_id => id})

이러한 쿼리는 모두 스스로 잘 작동합니다. 모두 반환 포스트 객체. 나는 하나의 ActiveRelation에이 게시물을 결합하고 싶습니다. 어떤 시점에서 수백 게시물의 수천이있을 수 있기 때문에,이 요구 사항은 데이터베이스 수준에서 수행 할 수 있습니다. 그것은 MySQL의 쿼리가 있다면, 나는 사용자 UNION 연산자를 간단하게 할 수있다. 내가 RoR에의 쿼리 인터페이스와 비슷한 할 수 있다면 사람은 알고 있나요?

해결법

  1. ==============================

    1.여기에 UNION 여러 범위로 할 수 있습니다 내가 쓴 빠른 작은 모듈입니다. 또한 액티브 :: 관계의 인스턴스로 결과를 반환합니다.

    여기에 UNION 여러 범위로 할 수 있습니다 내가 쓴 빠른 작은 모듈입니다. 또한 액티브 :: 관계의 인스턴스로 결과를 반환합니다.

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

    여기서 요지는 다음과 같습니다 https://gist.github.com/tlowrimore/5162327

    요청으로, 여기 UnionScope 작동하는 방법의 예입니다 :

    class Property < ActiveRecord::Base
      include ActiveRecord::UnionScope
    
      # some silly, contrived scopes
      scope :active_nearby,     -> { where(active: true).where('distance <= 25') }
      scope :inactive_distant,  -> { where(active: false).where('distance >= 200') }
    
      # A union of the aforementioned scopes
      scope :active_near_and_inactive_distant, -> { union_scope(active_nearby, inactive_distant) }
    end
    
  2. ==============================

    2.나는이 문제가 발생했고, 지금 내 이동 - 투 전략 (손이나 기존 범위에 to_sql를 사용하여) SQL을 생성하고 다음 절에서 그것을 충실하는 것입니다. 나는 그것이 더 효율적으로 귀하의 승인 된 방법보다입니다 보장 할 수 있지만, 눈에 상대적으로 쉽게 당신에게 정상적인 ARel 객체 등을 제공합니다.

    나는이 문제가 발생했고, 지금 내 이동 - 투 전략 (손이나 기존 범위에 to_sql를 사용하여) SQL을 생성하고 다음 절에서 그것을 충실하는 것입니다. 나는 그것이 더 효율적으로 귀하의 승인 된 방법보다입니다 보장 할 수 있지만, 눈에 상대적으로 쉽게 당신에게 정상적인 ARel 객체 등을 제공합니다.

    watched_news_posts = Post.joins(:news => :watched).where(:watched => {:user_id => id})
    watched_topic_posts = Post.joins(:post_topic_relationships => {:topic => :watched}).where(:watched => {:user_id => id})
    
    Post.from("(#{watched_news_posts.to_sql} UNION #{watched_topic_posts.to_sql}) AS posts")
    

    당신은뿐만 아니라 두 개의 서로 다른 모델이 작업을 수행 할 수 있습니다,하지만 당신은 확인해야 그들이 모두 UNION 내부 "같은 모양"- 당신이 있는지가 같은 열을 생산할 예정 만들기 위해 두 쿼리에서 선택한 사용할 수 있습니다.

    topics = Topic.select('user_id AS author_id, description AS body, created_at')
    comments = Comment.select('author_id, body, created_at')
    
    Comment.from("(#{comments.to_sql} UNION #{topics.to_sql}) AS comments")
    
  3. ==============================

    3.올리브 '답변에 따라, 나는이 문제에 다른 해결책을 마련했다. 그것은 해킹과 같은 약간의 비트를 느낀다,하지만 내가 처음에 후 무엇이다 ActiveRelation의 인스턴스를 반환합니다.

    올리브 '답변에 따라, 나는이 문제에 다른 해결책을 마련했다. 그것은 해킹과 같은 약간의 비트를 느낀다,하지만 내가 처음에 후 무엇이다 ActiveRelation의 인스턴스를 반환합니다.

    Post.where('posts.id IN 
          (
            SELECT post_topic_relationships.post_id FROM post_topic_relationships
              INNER JOIN "watched" ON "watched"."watched_item_id" = "post_topic_relationships"."topic_id" AND "watched"."watched_item_type" = "Topic" WHERE "watched"."user_id" = ?
          )
          OR posts.id IN
          (
            SELECT "posts"."id" FROM "posts" INNER JOIN "news" ON "news"."id" = "posts"."news_id" 
            INNER JOIN "watched" ON "watched"."watched_item_id" = "news"."id" AND "watched"."watched_item_type" = "News" WHERE "watched"."user_id" = ?
          )', id, id)
    

    사람이 본질적으로 세 개의 쿼리를 실행 있기 때문에,이를 최적화하거나 성능을 개선하기 위해 어떤 제안을 가지고 있으며, 약간의 중복을 느끼면 나는 아직도 그것을 감사하겠습니다.

  4. ==============================

    4.방법에 대한 ...

    방법에 대한 ...

    def union(scope1, scope2)
      ids = scope1.pluck(:id) + scope2.pluck(:id)
      where(id: ids.uniq)
    end
    
  5. ==============================

    5.또한 범위에 대한 노조 방법 액티브을 확장 브라이언 헴펠의 active_record_union 보석을 사용할 수 있습니다.

    또한 범위에 대한 노조 방법 액티브을 확장 브라이언 헴펠의 active_record_union 보석을 사용할 수 있습니다.

    귀하의 질의는 다음과 같이 될 것이다 :

    Post.joins(:news => :watched).
      where(:watched => {:user_id => id}).
      union(Post.joins(:post_topic_relationships => {:topic => :watched}
        .where(:watched => {:user_id => id}))
    

    희망이 결국 언젠가는 액티브로 통합됩니다.

  6. ==============================

    6.당신은을 사용하여 OR 대신에 UNION의 수 있을까요?

    당신은을 사용하여 OR 대신에 UNION의 수 있을까요?

    그럼 당신은 뭔가를 같이 할 수있는 :

    Post.joins(:news => :watched, :post_topic_relationships => {:topic => :watched})
    .where("watched.user_id = :id OR topic_watched.user_id = :id", :id => id)
    

    (당신이 있기 때문에 내가 너무 확실 테이블의 이름은 쿼리 일 무슨 아니에요 두 번 감시 테이블을 조인)

    조인이 많이 있기 때문에, 그것은 또한 데이터베이스에 매우 무거운 수도 있지만 최적화 할 수 있습니다.

  7. ==============================

    7.틀림없이, 이것은 가독성을 향상 시키지만, 반드시 성능 :

    틀림없이, 이것은 가독성을 향상 시키지만, 반드시 성능 :

    def my_posts
      Post.where <<-SQL, self.id, self.id
        posts.id IN 
        (SELECT post_topic_relationships.post_id FROM post_topic_relationships
        INNER JOIN watched ON watched.watched_item_id = post_topic_relationships.topic_id 
        AND watched.watched_item_type = "Topic" 
        AND watched.user_id = ?
        UNION
        SELECT posts.id FROM posts 
        INNER JOIN news ON news.id = posts.news_id 
        INNER JOIN watched ON watched.watched_item_id = news.id 
        AND watched.watched_item_type = "News" 
        AND watched.user_id = ?)
      SQL
    end
    

    이 같이 호출 할 수 있도록이 방법은 액티브 :: 관계를 반환합니다 :

    my_posts.order("watched_item_type, post.id DESC")
    
  8. ==============================

    8.active_record_union 보석이있다. 도움이 될 수

    active_record_union 보석이있다. 도움이 될 수

    https://github.com/brianhempel/active_record_union

    "게시물"을 선택합니다. * FROM (   "게시물"을 선택합니다. * "게시물", "게시물"FROM. "USER_ID"= 1   노동 조합   "게시물"SELECT * "게시물"FROM WHERE (published_at < '2014년 7월 19일 16 : 04 : 21.918366'). ) 게시물

  9. ==============================

    9.난 그냥 반환되는 레코드의 배열을 당신이 필요로하는 두 개의 쿼리를 실행하고 결합 할 것이다 :

    난 그냥 반환되는 레코드의 배열을 당신이 필요로하는 두 개의 쿼리를 실행하고 결합 할 것이다 :

    @posts = watched_news_posts + watched_topics_posts
    

    또는, 적어도 시험이 아웃시. 당신은 루비의 배열의 조합이 너무 느린 것입니다 생각하십니까? 이 문제를 해결하기 위해 제안 된 쿼리를 보면, 나는 성능 차이의 의미가있을 것이라고 확신하고 있지 않다.

  10. ==============================

    10.비슷한 경우 내가 두 배열을 합산 미나리를 사용 : paginate_array를 (). 아주 좋은 솔루션을 작업. 내가 같은 테이블에 다른 순서 () 두 개의 결과를 요약해야하기 때문에 나는) 여기서 (사용 할 수 없습니다.

    비슷한 경우 내가 두 배열을 합산 미나리를 사용 : paginate_array를 (). 아주 좋은 솔루션을 작업. 내가 같은 테이블에 다른 순서 () 두 개의 결과를 요약해야하기 때문에 나는) 여기서 (사용 할 수 없습니다.

  11. ==============================

    11.엘리엇 넬슨은 관계의 일부가 비어있는 경우를 제외하고, 좋은 대답했다. 나는 그런 일을 할 것입니다 :

    엘리엇 넬슨은 관계의 일부가 비어있는 경우를 제외하고, 좋은 대답했다. 나는 그런 일을 할 것입니다 :

    def union_2_relations(relation1,relation2)
    sql = ""
    if relation1.any? && relation2.any?
      sql = "(#{relation1.to_sql}) UNION (#{relation2.to_sql}) as #{relation1.klass.table_name}"
    elsif relation1.any?
      sql = relation1.to_sql
    elsif relation2.any?
      sql = relation2.to_sql
    end
    relation1.klass.from(sql)
    

    종료

  12. ==============================

    12.내가 레일 응용 프로그램에 대한 내 자신의 루비에 UNION을 사용하여 SQL 쿼리를 결합하는 방법을 Heres.

    내가 레일 응용 프로그램에 대한 내 자신의 루비에 UNION을 사용하여 SQL 쿼리를 결합하는 방법을 Heres.

    당신은 당신의 자신의 코드에 영감을 아래 사용할 수 있습니다.

    class Preference < ApplicationRecord
      scope :for, ->(object) { where(preferenceable: object) }
    end
    

    아래는 내가 함께 범위에 합류 UNION입니다.

      def zone_preferences
        zone = Zone.find params[:zone_id]
        zone_sql = Preference.for(zone).to_sql
        region_sql = Preference.for(zone.region).to_sql
        operator_sql = Preference.for(Operator.current).to_sql
    
        Preference.from("(#{zone_sql} UNION #{region_sql} UNION #{operator_sql}) AS preferences")
      end
    
  13. ==============================

    13.적은 문제를 쉽게 따를 :

    적은 문제를 쉽게 따를 :

        def union_scope(*scopes)
          scopes[1..-1].inject(where(id: scopes.first)) { |all, scope| all.or(where(id: scope)) }
        end
    

    그래서 결국 :

    union_scope(watched_news_posts, watched_topic_posts)
    
  14. from https://stackoverflow.com/questions/6686920/activerecord-query-union by cc-by-sa and MIT license