Rails에서는 ID가 있는 경우 데이터베이스에서 많은 레코드를 쉽게 얻을 수 있습니다.
Person.where(id: [1, 2, 3]).map(&:id) => [1, 2, 3]
하지만 레코드를 다른 주문? 검색 엔진이 가장 관련성이 높은 ID를 먼저 반환할 수도 있습니다. 어떻게 유지합니까? 당신의 기록은 순서대로?
where
를 시도할 수 있습니다. 다시:
Person.where(id: [2, 1, 3]).map(&:id) => [1, 2, 3]
그러나 그것은 전혀 작동하지 않습니다. 그래서 어떻게 기록을 올바른 순서로 되돌리셨나요?
호환 방식:case
진술
Ruby와 마찬가지로 SQL은 case...when
을 지원합니다. 진술.
자주 볼 수는 없지만 case...when
문장은 거의 해시처럼 행동합니다. 한 값을 다른 값에 매핑할 수 있습니다.
case :b
when :a then 1
when :b then 2
when :c then 3
end # => 2
이 case 문은 해시처럼 보입니다.
{
:a => 1,
:b => 2,
:c => 3
}[:b] # => 2
따라서 키가 표시되어야 하는 순서에 따라 키를 매핑하는 방법이 있습니다. 그리고 데이터베이스는 임의의 순서로 결과를 정렬하고 반환할 수 있습니다.
이를 알고 있으면 ID와 해당 위치를 case
에 넣을 수 있습니다. 명령문을 작성하고 SQL order
에서 사용합니다. 조항.
따라서 [2, 1, 3] 순서로 개체를 반환하려는 경우 SQL은 다음과 같을 수 있습니다.
SELECT * FROM people
WHERE id IN (1, 2, 3)
ORDER BY CASE id
WHEN 2 THEN 0
WHEN 1 THEN 1
WHEN 3 THEN 2
ELSE 3 END;
그렇게 하면 레코드가 올바른 순서로 반환됩니다. case
각 ID를 반환해야 하는 순서로 변환합니다.
물론, 그것은 우스꽝스럽게 보입니다. 그리고 그런 조항을 손으로 만드는 것이 얼마나 성가신 일인지 상상할 수 있을 것입니다.
하지만 없다. 손으로 구축합니다. 이것이 Ruby의 장점입니다.
module Extensions::ActiveRecord::FindByOrderedIds
extend ActiveSupport::Concern
module ClassMethods
def find_ordered(ids)
order_clause = "CASE id "
ids.each_with_index do |id, index|
order_clause << sanitize_sql_array(["WHEN ? THEN ? ", id, index])
end
order_clause << sanitize_sql_array(["ELSE ? END", ids.length])
where(id: ids).order(order_clause)
end
end
end
ActiveRecord::Base.include(Extensions::ActiveRecord::FindByOrderedIds)
Person.find_ordered([2, 1, 3]) # => [2, 1, 3]
정확히 우리가 원했던 방식입니다!
더 깨끗하고 MySQL 전용 방식
MySQL을 사용하는 경우 더 깔끔한 방법이 있습니다. MySQL에는 특별한 ORDER BY FIELD
가 있습니다. 구문:
SELECT * FROM people
WHERE id IN (1, 2, 3)
ORDER BY FIELD(id, 2, 1, 3);
Ruby에서 생성할 수도 있습니다.
module Extensions::ActiveRecord::FindByOrderedIds
extend ActiveSupport::Concern
module ClassMethods
def find_ordered(ids)
sanitized_id_string = ids.map {|id| connection.quote(id)}.join(",")
where(id: ids).order("FIELD(id, #{sanitized_id_string})")
end
end
end
ActiveRecord::Base.include(Extensions::ActiveRecord::FindByOrderedIds)
따라서 MySQL을 사용하고 있고 호환성에 대해 너무 걱정하지 않는다면 이것이 좋은 방법입니다. 이러한 진술이 로그를 통해 전달되기 때문에 훨씬 더 읽기 쉽습니다.
특정 임의의 순서로 레코드를 표시하려면 Ruby에서 정렬할 필요가 없습니다. 약간의 코드 스니펫만 있으면 데이터베이스에서 데이터를 찾고, 정렬하고, 앱으로 반환하는 작업을 수행할 수 있습니다.