복붙노트

[RUBY-ON-RAILS] 액티브을 찾을 청소 방법은 지정된 순서대로 id로 객체

RUBY-ON-RAILS

액티브을 찾을 청소 방법은 지정된 순서대로 id로 객체

나는 ID의 배열의 지정된 객체 액티브의 배열을 가져올.

나는 가정

Object.find([5,2,3])

객체 5, 오브젝트 2 배열을 반환, 다음 순서대로 3 개체, 대신 나는 배열 오브젝트 2, 오브젝트 3으로 주문 후 5 개체를 얻을.

액티브 자료 찾기 방법 API는 (다른 문서가이 경고를 제공하지 않습니다)에서 제공하는 순서를 기대하지해야한다고 언급하고있다.

하나 개의 잠재적 인 솔루션은 같은 순서로 ID의 배열에 의해 찾기에 주어진?하지만 주문 옵션은 SQLite는 유효하지 않는 것 같습니다.

나는 (중 다소 간단하고 제대로 스케일링 또는 더 나은 스케일링 더 복잡한) 객체 자신을 정렬하는 일부 루비 코드를 작성하지만, 더 좋은 방법이 할 수 있습니까?

해결법

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

    1.그것은 그들이 일종의을하지 않는이다, MySQL과 다른 DB를 자신의 물건을 분류하는 것이 아니다. 당신이 Model.find를 호출 할 때 ([5, 2, 3), 생성 된 SQL은 같은 것입니다 :

    그것은 그들이 일종의을하지 않는이다, MySQL과 다른 DB를 자신의 물건을 분류하는 것이 아니다. 당신이 Model.find를 호출 할 때 ([5, 2, 3), 생성 된 SQL은 같은 것입니다 :

    SELECT * FROM models WHERE models.id IN (5, 2, 3)
    

    이 주문, 당신은 반환하려는 레코드를 바로 설정을 지정하지 않습니다. 그것은 일반적으로 MySQL은 'ID'위해 데이터베이스 행을 반환 것이라고 밝혀,하지만이의 보장은 없습니다.

    보장 된 순서대로 반환 레코드에 대한 데이터베이스를 얻을 수있는 유일한 방법은 주문 절을 추가하는 것입니다. 귀하의 기록은 항상 특정 순서로 반환 될 경우에, 당신은 DB에 정렬 열을 추가하고 Model.find을 수행 할 수 있습니다 ([5, 2, 3] : 순서 => '열 _'). 그렇지 않은 경우, 당신은 코드에서 정렬을해야 할 것이다 :

    ids = [5, 2, 3]
    records = Model.find(ids)
    sorted_records = ids.collect {|id| records.detect {|x| x.id == id}} 
    
  2. ==============================

    2.제론 반 디크 내 이전 의견을 바탕으로이보다 효율적이고 each_with_object를 사용하여 두 개의 선에서 할 수있는

    제론 반 디크 내 이전 의견을 바탕으로이보다 효율적이고 each_with_object를 사용하여 두 개의 선에서 할 수있는

    result_hash = Model.find(ids).each_with_object({}) {|result,result_hash| result_hash[result.id] = result }
    ids.map {|id| result_hash[id]}
    

    여기에 참고로 사용되는 벤치 마크 내가있다

    ids = [5,3,1,4,11,13,10]
    results = Model.find(ids)
    
    Benchmark.measure do 
      100000.times do 
        result_hash = results.each_with_object({}) {|result,result_hash| result_hash[result.id] = result }
        ids.map {|id| result_hash[id]}
      end
    end.real
    #=>  4.45757484436035 seconds
    

    이제 다른 하나

    ids = [5,3,1,4,11,13,10]
    results = Model.find(ids)
    Benchmark.measure do 
      100000.times do 
        ids.collect {|id| results.detect {|result| result.id == id}}
      end
    end.real
    # => 6.10875988006592
    

    최신 정보

    당신은 대부분의 순서와 경우 문을 사용하여이 작업을 수행 할 수 있습니다, 여기 당신이 사용할 수있는 수준의 방법이다.

    def self.order_by_ids(ids)
      order_by = ["case"]
      ids.each_with_index.map do |id, index|
        order_by << "WHEN id='#{id}' THEN #{index}"
      end
      order_by << "end"
      order(order_by.join(" "))
    end
    
    #   User.where(:id => [3,2,1]).order_by_ids([3,2,1]).map(&:id) 
    #   #=> [3,2,1]
    
  3. ==============================

    3.분명히 MySQL과 자신의 다른 DB 관리 시스템 정렬 것. 난 당신이 우회를 수행 할 수 있다고 생각 :

    분명히 MySQL과 자신의 다른 DB 관리 시스템 정렬 것. 난 당신이 우회를 수행 할 수 있다고 생각 :

    ids = [5,2,3]
    @things = Object.find( ids, :order => "field(id,#{ids.join(',')})" )
    
  4. ==============================

    4.휴대용 솔루션은 주문 BY에서 SQL의 CASE 문을 사용하는 것입니다. 당신은 ORDER BY에 거의 어떤 표현을 사용할 수 있으며, CASE는 인라인 조회 테이블로 사용할 수 있습니다. 예를 들어,이 후하고있는 SQL은 다음과 같이 보일 것이다 :

    휴대용 솔루션은 주문 BY에서 SQL의 CASE 문을 사용하는 것입니다. 당신은 ORDER BY에 거의 어떤 표현을 사용할 수 있으며, CASE는 인라인 조회 테이블로 사용할 수 있습니다. 예를 들어,이 후하고있는 SQL은 다음과 같이 보일 것이다 :

    select ...
    order by
        case id
        when 5 then 0
        when 2 then 1
        when 3 then 2
        end
    

    즉 루비의 비트와 함께 생성하는 매우 쉽습니다 :

    ids = [5, 2, 3]
    order = 'case id ' + (0 .. ids.length).map { |i| "when #{ids[i]} then #{i}" }.join(' ') + ' end'
    

    위는 당신이 숫자 또는 IDS에서 다른 안전한 값으로 작업하는 것으로 가정; 그런 경우가 아니라면 당신은 제대로 ID를 인용에 connection.quote 또는 액티브 SQL의 소독 방법 중 하나를 사용하고자하는 것입니다.

    그런 다음 주문 조건으로 주문 문자열을 사용하십시오

    Object.find(ids, :order => order)
    

    또는 현대 세계 :

    Object.where(:id => ids).order(order)
    

    이것은 조금 장황하지만 모든 SQL 데이터베이스와 동일하게 작동해야하며 어려운 추함을 숨길 것이 아니다.

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

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

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

    Object.where(id: [5, 2, 3]).order_as_specified(id: [5, 2, 3])
    

    그냥 테스트는 SQLite는 작동합니다.

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

    6.저스틴 와이즈은 이틀 전에이 문제에 대한 블로그 글을 썼다.

    저스틴 와이즈은 이틀 전에이 문제에 대한 블로그 글을 썼다.

    선호하는 순서에 대한 데이터베이스를 이야기하고 데이터베이스에서 직접 순서대로 정렬 된 모든 레코드를로드 할 수있는 좋은 방법이 될 것으로 보인다. 자신의 블로그 기사에서 예 :

    # in config/initializers/find_by_ordered_ids.rb
    module FindByOrderedIdsActiveRecordExtension
      extend ActiveSupport::Concern
      module ClassMethods
        def find_ordered(ids)
          order_clause = "CASE id "
          ids.each_with_index do |id, index|
            order_clause << "WHEN #{id} THEN #{index} "
          end
          order_clause << "ELSE #{ids.length} END"
          where(id: ids).order(order_clause)
        end
      end
    end
    
    ActiveRecord::Base.include(FindByOrderedIdsActiveRecordExtension)
    

    즉 쓰기에 당신을 수 있습니다 :

    Object.find_ordered([2, 1, 3]) # => [2, 1, 3]
    
  7. ==============================

    7.다음과 같은 방법 (! 검출 같이 해시 룩업 아닌 O (n)이 배열 됨) 한 라이너 확대됨가있다 :

    다음과 같은 방법 (! 검출 같이 해시 룩업 아닌 O (n)이 배열 됨) 한 라이너 확대됨가있다 :

    def find_ordered(model, ids)
      model.find(ids).map{|o| [o.id, o]}.to_h.values_at(*ids)
    end
    
    # We get:
    ids = [3, 3, 2, 1, 3]
    Model.find(ids).map(:id)          == [1, 2, 3]
    find_ordered(Model, ids).map(:id) == ids
    
  8. ==============================

    8.또 다른 (아마도 더 효율적으로) 방법은 루비에서 할 수 있습니다 :

    또 다른 (아마도 더 효율적으로) 방법은 루비에서 할 수 있습니다 :

    ids = [5, 2, 3]
    records_by_id = Model.find(ids).inject({}) do |result, record| 
      result[record.id] = record
      result
    end
    sorted_records = ids.map {|id| records_by_id[id] }
    
  9. ==============================

    9.여기에 내가 가지고 올 수있는 간단한 일이있다 :

    여기에 내가 가지고 올 수있는 간단한 일이있다 :

    ids = [200, 107, 247, 189]
    results = ModelObject.find(ids).group_by(&:id)
    sorted_results = ids.map {|id| results[id].first }
    
  10. ==============================

    10.

    @things = [5,2,3].map{|id| Object.find(id)}
    

    이것은 각 ID에 대한 데이터베이스로 여행을 필요로하기 때문에 당신이 찾을 수있는 너무 많은 개체가없는 가정, 아마도 가장 쉬운 방법입니다.

  11. from https://stackoverflow.com/questions/801824/clean-way-to-find-activerecord-objects-by-id-in-the-order-specified by cc-by-sa and MIT license