रेल में, यदि आपके पास उनके आईडी हैं, तो आपके डेटाबेस से रिकॉर्ड का एक गुच्छा प्राप्त करना आसान है:
Person.where(id: [1, 2, 3]).map(&:id) => [1, 2, 3]
लेकिन क्या होगा यदि आप रिकॉर्ड को भिन्न में वापस पाना चाहते हैं आदेश? हो सकता है कि आपका खोज इंजन सबसे अधिक प्रासंगिक आईडी पहले लौटाए। आप कैसे रखते हैं उस क्रम में आपके रिकॉर्ड?
आप कोशिश कर सकते हैं where
फिर से:
Person.where(id: [2, 1, 3]).map(&:id) => [1, 2, 3]
लेकिन यह बिल्कुल भी काम नहीं करता है। तो कैसे करें आपको अपने रिकॉर्ड सही क्रम में वापस मिलते हैं?
संगत तरीका:case
बयान
रूबी की तरह ही, SQL case...when
का समर्थन करता है बयान।
आप इसे बहुत बार नहीं देखते हैं, लेकिन case...when
बयान लगभग कर सकते हैं हैश की तरह कार्य करें। आप एक मान को दूसरे में मैप कर सकते हैं:
case :b
when :a then 1
when :b then 2
when :c then 3
end # => 2
वह केस स्टेटमेंट हैश जैसा दिखता है:
{
:a => 1,
:b => 2,
:c => 3
}[:b] # => 2
तो, आपके पास चाबियों को मैप करने का एक तरीका है ताकि वे क्रम में दिखें। और आपका डेटाबेस उस मनमाने क्रम से आपके परिणामों को क्रमबद्ध और वापस कर सकता है।
यह जानकर, आप अपनी आईडी और उनकी स्थिति को 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
प्रत्येक आईडी को उस क्रम में बदल देता है जिस क्रम में उसे वापस किया जाना चाहिए।
बेशक, यह हास्यास्पद लगता है। और आप सोच सकते हैं कि इस तरह के एक खंड को हाथ से बनाना कितना कष्टप्रद होगा।
लेकिन आपके पास है . नहीं है इसे हाथ से बनाने के लिए। रूबी के लिए यही है:
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);
आप इसे रूबी से भी उत्पन्न कर सकते हैं:
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 का उपयोग कर रहे हैं, और संगतता के बारे में बहुत चिंतित नहीं हैं, तो यह एक अच्छा तरीका है। इसे पढ़ना बहुत आसान है, क्योंकि ये कथन आपके लॉग्स के माध्यम से उड़ते हैं।
जब आप किसी विशिष्ट, मनमाने क्रम में रिकॉर्ड प्रदर्शित करना चाहते हैं, तो आपको उन्हें रूबी में क्रमबद्ध करने की आवश्यकता नहीं है। एक छोटे से कोड स्निपेट के साथ, आप डेटाबेस को वह करने दे सकते हैं जो इसमें अच्छा है:अपने ऐप में डेटा ढूंढना, सॉर्ट करना और वापस करना।