2011-12-14 13 views
9

द्वारा ActiveRecord ऑर्डर मेरे पास कुछ बाहरी स्टोरेज (रेल कैश या रेडिस) में संग्रहीत आईडी की एक सरणी है। नियंत्रक की कार्रवाई में मैं यहबाहरी सरणी

ids = [5, 1, 17, 84] # really fetched from external source 
result = MyModel.where(:id => ids) 

उपयोग करते हुए, यानी इस डेटा का चयन करें और वस्तु लाने मैं भी चाहता हूँ यह array_of आईडी में आईडी के रूप में सिर्फ एक ही आदेश दिया जा करने के लिए:

ids == result.map(&:id) # => true 

वैकल्पिक हल मैं द्वारा छँटाई उपयोग के रूप में mysql क्षेत्र समारोह:

MyModel.where(:id => ids).order("FIELD(id, #{ids.join ', '})") 

लेकिन मैं इस दृष्टिकोण पसंद नहीं है के रूप में यह mysql विशिष्ट है और बड़ा ids सरणी के मामले में बहुत लंबे प्रश्नों पैदा करता है। क्या बेहतर है, डीबी-अज्ञेयवादी तरीके से ऐसा करने के लिए? डीबी से अपरिवर्तित डेटा प्राप्त करना और रूबी पक्ष पर सॉर्ट करना अवांछनीय है क्योंकि यह संसाधन-महंगा और पेजिनेशन के साथ उपयोग करना मुश्किल है।

धन्यवाद।

+1

की संभावित डुप्लिकेट [ActiveRecord.find (सरणी \ _OF \ _ids), संरक्षण आदेश] (https: // stackoverflow। कॉम/प्रश्न/1680627/activerecord-findarray-of-ids-preserving-order) – MatayoshiMariano

उत्तर

0

यदि सरणी का क्रम हमेशा समान होता है तो आप डेटाबेस तालिका में कैश किए गए ऑर्डर कॉलम जोड़ सकते हैं।

MyModel.order ("cached_order")

+0

दुर्भाग्यवश यह नहीं है। आईडी के ऐरे तेजी से बदलते हैं। उदाहरण के लिए यह Redis में संग्रहीत अंतिम बार गए # शो पृष्ठों की सूची हो सकती है। – Ineu

4

आप एक ActiveRecord संग्रह के बजाय एक सरणी प्राप्त करने से परहेज नहीं करते हैं, तो आप उपयोग कर सकते हैं:

result = MyModel.find(ids).sort_by {|m| ids.index(m.id)} 
9

मैं सिर्फ एक मणि जारी किया (order_as_specified) कि आप इस तरह से देशी एसक्यूएल आदेश करने के लिए अनुमति देता है:

MyModel.where(id: ids).order_as_specified(id: ids) 

यह एक ActiveRecord संबंध देता है, और इस तरह अन्य तरीकों के साथ श्रृंखलित जा सकता है:

MyModel.where(id: ids).order_as_specified(id: ids).limit(3) 

आप उत्सुक हैं, तो हुड के नीचे यह निर्माण किया गया:

... ORDER BY ID='5' DESC, ID='1' DESC, ID='17' DESC, ID='84' DESC 
+1

यह काफी चालाक समाधान है। एक मणि जोड़ने के बजाय, मैंने अपने मामले के लिए एक साधारण एक-लाइनर लिखा है जो मुझे चाहिए: 'sql = ids.map.with_index {| id, index | सूचकांक == ids.length - 1? "आईडी = '# {आईडी}' डीईएससी": "आईडी = '# {आईडी}' डीईएससी,"}। जॉइन ('') '। प्रेरणा के लिए धन्यवाद! – ACIDSTEALTH

+0

खुशी है कि यह आपके लिए @ACIDSTEALTH काम करता है! – JacobEvelyn