[RUBY-ON-RAILS] 액티브을 찾을 청소 방법은 지정된 순서대로 id로 객체
RUBY-ON-RAILS액티브을 찾을 청소 방법은 지정된 순서대로 id로 객체
나는 ID의 배열의 지정된 객체 액티브의 배열을 가져올.
나는 가정
Object.find([5,2,3])
객체 5, 오브젝트 2 배열을 반환, 다음 순서대로 3 개체, 대신 나는 배열 오브젝트 2, 오브젝트 3으로 주문 후 5 개체를 얻을.
액티브 자료 찾기 방법 API는 (다른 문서가이 경고를 제공하지 않습니다)에서 제공하는 순서를 기대하지해야한다고 언급하고있다.
하나 개의 잠재적 인 솔루션은 같은 순서로 ID의 배열에 의해 찾기에 주어진?하지만 주문 옵션은 SQLite는 유효하지 않는 것 같습니다.
나는 (중 다소 간단하고 제대로 스케일링 또는 더 나은 스케일링 더 복잡한) 객체 자신을 정렬하는 일부 루비 코드를 작성하지만, 더 좋은 방법이 할 수 있습니까?
해결법
-
==============================
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.제론 반 디크 내 이전 의견을 바탕으로이보다 효율적이고 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.분명히 MySQL과 자신의 다른 DB 관리 시스템 정렬 것. 난 당신이 우회를 수행 할 수 있다고 생각 :
분명히 MySQL과 자신의 다른 DB 관리 시스템 정렬 것. 난 당신이 우회를 수행 할 수 있다고 생각 :
ids = [5,2,3] @things = Object.find( ids, :order => "field(id,#{ids.join(',')})" )
-
==============================
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.내가 여기에 대답, 나는 당신이이 같은 네이티브 SQL 순서를 수행 할 수 있습니다 보석 (order_as_specified)를 출시 :
내가 여기에 대답, 나는 당신이이 같은 네이티브 SQL 순서를 수행 할 수 있습니다 보석 (order_as_specified)를 출시 :
Object.where(id: [5, 2, 3]).order_as_specified(id: [5, 2, 3])
그냥 테스트는 SQLite는 작동합니다.
-
==============================
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.다음과 같은 방법 (! 검출 같이 해시 룩업 아닌 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.또 다른 (아마도 더 효율적으로) 방법은 루비에서 할 수 있습니다 :
또 다른 (아마도 더 효율적으로) 방법은 루비에서 할 수 있습니다 :
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.여기에 내가 가지고 올 수있는 간단한 일이있다 :
여기에 내가 가지고 올 수있는 간단한 일이있다 :
ids = [200, 107, 247, 189] results = ModelObject.find(ids).group_by(&:id) sorted_results = ids.map {|id| results[id].first }
-
==============================
10.
@things = [5,2,3].map{|id| Object.find(id)}
이것은 각 ID에 대한 데이터베이스로 여행을 필요로하기 때문에 당신이 찾을 수있는 너무 많은 개체가없는 가정, 아마도 가장 쉬운 방법입니다.
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
'RUBY-ON-RAILS' 카테고리의 다른 글
[RUBY-ON-RAILS] 중첩 된 PARAMS 해시에 무기 호에 메소드를 호출 피하기 위해 깨끗한 방법이 있나요? [복제] (0) | 2020.02.09 |
---|---|
[RUBY-ON-RAILS] 삭제 링크 레일 3보기 대신에 "삭제"의 "가져 오기"전송 (0) | 2020.02.08 |
[RUBY-ON-RAILS] 레일 오류에 루비를 처리하는 방법 : " '보석 액티브 - PostgreSQL의 어댑터를 설치`PostgreSQL의 어댑터를 설치하십시오" (0) | 2020.02.08 |
[RUBY-ON-RAILS] 어떻게 레일 URL 헬퍼에 대한 기본 호스트를 설정합니까? (0) | 2020.02.08 |
[RUBY-ON-RAILS] 액티브 Arel OR 조건 (0) | 2020.02.08 |