복붙노트

[RUBY-ON-RAILS] ActiveRecord.find (array_of_ids), 보존하기 위해

RUBY-ON-RAILS

ActiveRecord.find (array_of_ids), 보존하기 위해

당신이 레일에서 Something.find (array_of_ids를) 할 때, 결과 배열의 순서는 array_of_ids의 순서에 의존하지 않습니다.

순서를 찾기를하고 보존 할 수있는 방법이 있습니까?

ATM 내가 수동으로 정렬 ID의 순서에 따라 기록,하지만 그 종류 절름발이이다.

UPD : 어떻게 한 후, 주문 PARAM 및 SQL 구문의 일종 : 그것은을 사용하여 순서를 지정할 수 있는지?

해결법

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

    1.대답은 MySQL 용 만

    대답은 MySQL 용 만

    mysql을 불리는 필드에서 함수) (이

    다음은 () .find에서 사용할 수있는 방법입니다 :

    >> ids = [100, 1, 6]
    => [100, 1, 6]
    
    >> WordDocument.find(ids).collect(&:id)
    => [1, 6, 100]
    
    >> WordDocument.find(ids, :order => "field(id, #{ids.join(',')})")
    => [100, 1, 6]
    
    For new Version
    >> WordDocument.where(id: ids).order("field(id, #{ids.join ','})")
    
  2. ==============================

    2.이상하게도, 아무도는 다음과 같이 제안하지 않았다 :

    이상하게도, 아무도는 다음과 같이 제안하지 않았다 :

    index = Something.find(array_of_ids).group_by(&:id)
    array_of_ids.map { |i| index[i].first }
    

    이 SQL 백엔드를시키는 외에수록 효율적으로 그것을한다.

    편집 : 내 자신의 대답을 개선하기 위해, 당신은 또한 다음과 같이 그것을 할 수 있습니다 :

    Something.find(array_of_ids).index_by(&:id).slice(*array_of_ids).values
    

    #index_by 및 #slice는 각각 배열과 해시에 대한 ActiveSupport에 매우 편리 추가됩니다.

  3. ==============================

    3.마이크 우드 하우스는 그의 대답에 명시된 바와 같이,이 ID가에 ... 절 한 쿼리에서 모든 레코드를 검색 할 WHERE 후드, 레일이 포함 된 SQL 쿼리를 사용하고, becase 발생합니다. 이 빠른 개별적으로 각각의 ID를 검색하는 것보다,하지만 당신은 눈치 당신이 검색하는 레코드의 순서를 유지하지 않습니다.

    마이크 우드 하우스는 그의 대답에 명시된 바와 같이,이 ID가에 ... 절 한 쿼리에서 모든 레코드를 검색 할 WHERE 후드, 레일이 포함 된 SQL 쿼리를 사용하고, becase 발생합니다. 이 빠른 개별적으로 각각의 ID를 검색하는 것보다,하지만 당신은 눈치 당신이 검색하는 레코드의 순서를 유지하지 않습니다.

    이 문제를 해결하기 위해, 당신은 레코드를 찾을 때 사용한 ID의 원래 목록에 따라 응용 프로그램 수준에서 레코드를 정렬 할 수 있습니다.

    다른 배열의 요소에 따라 배열을 정렬하기 위해 많은 훌륭한 답변을 바탕으로, 나는 다음과 같은 솔루션을 권장합니다 :

    Something.find(array_of_ids).sort_by{|thing| array_of_ids.index thing.id}
    

    당신이 뭔가 좀 더 빠른 (하지만 틀림없이 다소 덜 읽을 수있는)을해야하는 경우 또는 당신이 할 수 있습니다 :

    Something.find(array_of_ids).index_by(&:id).values_at(*array_of_ids)
    
  4. ==============================

    4.이것은 PostgreSQL의 (소스)에 대한 작동하는 것 같다 -와 액티브 관계를 반환

    이것은 PostgreSQL의 (소스)에 대한 작동하는 것 같다 -와 액티브 관계를 반환

    class Something < ActiveRecrd::Base
    
      scope :for_ids_with_order, ->(ids) {
        order = sanitize_sql_array(
          ["position((',' || id::text || ',') in ?)", ids.join(',') + ',']
        )
        where(:id => ids).order(order)
      }    
    end
    
    # usage:
    Something.for_ids_with_order([1, 3, 2])
    

    예를 들면, 물론 다른 컬럼에 대해 확장 될 수있다 이름 열, 사용 위치에 대한 (에 이름 : 텍스트?) ...

  5. ==============================

    5.내가 여기에 대답, 나는 당신이이 같은 네이티브 SQL 순서를 수행 할 수 있습니다 보석 (order_as_specified)를 출시 :

    내가 여기에 대답, 나는 당신이이 같은 네이티브 SQL 순서를 수행 할 수 있습니다 보석 (order_as_specified)를 출시 :

    Something.find(array_of_ids).order_as_specified(id: array_of_ids)
    

    내가 테스트 할 수있었습니다까지로, 모든 RDBMS에서에서 기본적으로 작동하고, 그것을 체인 수있는 액티브 관계를 반환합니다.

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

    6.이 독점적 인 기술을 사용하여 작동하게 할 수있는 방법은 아마이 있지만 불가능 SQL에서 불행하게도 모든 경우에 작동 것이라고는, 당신도, 루비의 각 레코드 또는 주문에 대한 하나의 발견을 작성해야합니다 :

    이 독점적 인 기술을 사용하여 작동하게 할 수있는 방법은 아마이 있지만 불가능 SQL에서 불행하게도 모든 경우에 작동 것이라고는, 당신도, 루비의 각 레코드 또는 주문에 대한 하나의 발견을 작성해야합니다 :

    첫 번째 예 :

    sorted = arr.inject([]){|res, val| res << Model.find(val)}
    

    매우 비효율적

    두 번째 예 :

    unsorted = Model.find(arr)
    sorted = arr.inject([]){|res, val| res << unsorted.detect {|u| u.id == val}}
    
  7. ==============================

    7.@Gunchars 대답은 매우 중요하지만, 해시 클래스가 정렬되지 않기 때문에 그것은 레일 2.3 상자 밖으로 작동하지 않습니다. 간단한 해결 방법은 OrderedHash 클래스를 사용하는 index_by '열거 가능한 클래스를 확장하는 것입니다 :

    @Gunchars 대답은 매우 중요하지만, 해시 클래스가 정렬되지 않기 때문에 그것은 레일 2.3 상자 밖으로 작동하지 않습니다. 간단한 해결 방법은 OrderedHash 클래스를 사용하는 index_by '열거 가능한 클래스를 확장하는 것입니다 :

    module Enumerable
      def index_by_with_ordered_hash
        inject(ActiveSupport::OrderedHash.new) do |accum, elem|
          accum[yield(elem)] = elem
          accum
        end
      end
      alias_method_chain :index_by, :ordered_hash
    end
    

    이제 @Gunchars '접근 방식은 작동합니다

    Something.find(array_of_ids).index_by(&:id).slice(*array_of_ids).values
    

    보너스

    module ActiveRecord
      class Base
        def self.find_with_relevance(array_of_ids)
          array_of_ids = Array(array_of_ids) unless array_of_ids.is_a?(Array)
          self.find(array_of_ids).index_by(&:id).slice(*array_of_ids).values
        end
      end
    end
    

    그때

    Something.find_with_relevance(array_of_ids)
    
  8. ==============================

    8.가정 Model.pluck (: ID)를 반환 [1,2,3,4] 당신이 순서를 원하는 [2,4,1,3]

    가정 Model.pluck (: ID)를 반환 [1,2,3,4] 당신이 순서를 원하는 [2,4,1,3]

    개념은 언제 SQL 절 CASE BY 순서를 활용하는 것입니다. 예를 들면 :

    SELECT * FROM colors
      ORDER BY
      CASE
        WHEN code='blue' THEN 1
        WHEN code='yellow' THEN 2
        WHEN code='green' THEN 3
        WHEN code='red' THEN 4
        ELSE 5
      END, name;
    

    레일, 당신은 유사한 구조를 구성하는 모델의 공개 방법을함으로써이를 달성 할 수 있습니다 :

    def self.order_by_ids(ids)
      if ids.present?
        order_by = ["CASE"]
        ids.each_with_index do |id, index|
          order_by << "WHEN id='#{id}' THEN #{index}"
        end
        order_by << "END"
        order(order_by.join(" "))
      end
    else
      all # If no ids, just return all
    end
    

    그런 다음을 수행하십시오

    ordered_by_ids = [2,4,1,3]
    
    results = Model.where(id: ordered_by_ids).order_by_ids(ordered_by_ids)
    
    results.class # Model::ActiveRecord_Relation < ActiveRecord::Relation
    

    이것에 대해 좋은 점. 결과는 액티브 관계로 반환됩니다 (마지막으로, 수,, 당기기, 등 같은 방법을 사용할 수 있도록)

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

    9.네이티브 SQL 쿼리를 사용하여 효율적으로 할 수있는 보석 find_with_order이있다.

    네이티브 SQL 쿼리를 사용하여 효율적으로 할 수있는 보석 find_with_order이있다.

    그리고 그것은 MySQL과 PostgreSQL을 모두 지원합니다.

    예를 들면 :

    Something.find_with_order(array_of_ids)
    

    당신은 관계를 원하는 경우 :

    Something.where_with_order(:id, array_of_ids)
    
  10. ==============================

    10.후드 아래에 id를 통해 반복보다 더 효율적으로해야 WHERE ID를 ... 절과 함께 SELECT를 생성합니다 ID의 배열을 찾을 수 있습니다.

    후드 아래에 id를 통해 반복보다 더 효율적으로해야 WHERE ID를 ... 절과 함께 SELECT를 생성합니다 ID의 배열을 찾을 수 있습니다.

    그래서 요청은 데이터베이스에 하나의 여행에 만족하지만, ORDER BY 절없이 및 선택 정렬되지 않은 있습니다됩니다. 액티브는 다음과 같이이, 그래서 우리는 우리의 발견을 확장 이해 :

    Something.find(array_of_ids, :order => 'id')
    

    배열의 ID의 순서는 임의적이고 의미가 있다면 나는 당신이 결과를 가공 우편으로 최고의 서버가 될 거라고 생각 (즉, 당신은 행의 순서에 관계없이 ID의 순서의 배열에 맞게 반환 안에 포함합니다) 주문 절 있지만 어려워 모든 의도-계시에 복잡하지 될 것이다 : - 코드 당신은을 만들 수있다.

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

    11.나는 그것이 CHANGELOG 어디서나 언급이 표시되지 않지만이 기능은 버전 5.2.0의 출시와 함께 변경 것처럼, 그것은 보인다.

    나는 그것이 CHANGELOG 어디서나 언급이 표시되지 않지만이 기능은 버전 5.2.0의 출시와 함께 변경 것처럼, 그것은 보인다.

    여기 문서는 또한 버전 5.0으로 백 포트 된 것으로 나타납니다 그러나 5.2.0 태그 갱신 한 커밋.

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

    12.여기에 대한 대답을 참조

    여기에 대한 대답을 참조

    Object.where (ID : IDS) .order ( " '# {ids.join ('의 위치 (ID : 텍스트 ')}')") PostgreSQL을 작동합니다.

  13. ==============================

    13.발견의 주문 조항이있다 (: 순서 => '...') 레코드를 가져올 때이 작업을 수행한다. 당신은 또한 여기에서 도움을받을 수 있습니다.

    발견의 주문 조항이있다 (: 순서 => '...') 레코드를 가져올 때이 작업을 수행한다. 당신은 또한 여기에서 도움을받을 수 있습니다.

    링크 텍스트

  14. from https://stackoverflow.com/questions/1680627/activerecord-findarray-of-ids-preserving-order by cc-by-sa and MIT license