如果来自表格的ID,我有一个数组:
b = [659, 658, 656, 645, 644, 657, 634, 643, 649, 650, 651, 636, 633, 607, 605, 604, 648, 647, 675, 674, 667, 499]
我用它来检索来自tat table的对象列表:
k = Photo.where(id:b)
我得到的是一个对象列表,它们的排序顺序与数组不同。
我该怎么做?
答案 0 :(得分:2)
k = Photo.where(id: b).index_by(&:id).values_at(*b)
示例:
b = [5,3,1]
Country.where(id: b)
#=> [#<Country id: 1, name: "France">, #<Country id: 3, name: "Ukraine">, #<Country id: 5, name: "Spain">]
Country.where(id: b).index_by(&:id)
#=> {1=>#<Country id: 1, name: "France">, 3=>#<Country id: 3, name: "Ukraine">, 5=>#<Country id: 5, name: "Spain">}
Country.where(id: b).index_by(&:id).values_at(*b)
#=> [#<Country id: 5, name: "Spain">, #<Country id: 3, name: "Ukraine">, #<Country id: 1, name: "France">]
使用b = [5,3,3,1]
,第一个方法将输出:
#=> [#<Country id: 5, name: "Spain">, #<Country id: 3, name: "Ukraine">, #<Country id: 3, name: "Ukraine">, #<Country id: 1, name: "France">]
k = Photo.where(id: b).index_by(&:id).slice(*b).values
使用:
b = [5,3,3,1]
Country.where(id: b)
#=> [#<Country id: 1, name: "France">, #<Country id: 3, name: "Ukraine">, #<Country id: 5, name: "Spain">]
Country.where(id: b).index_by(&:id)
#=> {1=>#<Country id: 1, name: "France">, 3=>#<Country id: 3, name: "Ukraine">, 5=>#<Country id: 5, name: "Spain">}
Country.where(id: b).index_by(&:id).slice(*b)
#=> {5=>#<Country id: 5, name: "Spain">, 3=>#<Country id: 3, name: "Ukraine">, 1=>#<Country id: 1, name: "France">}
Country.where(id: b).index_by(&:id).slice(*b).values
#=> [#<Country id: 5, name: "Spain">, #<Country id: 3, name: "Ukraine">, #<Country id: 1, name: "France">]
当然,您也可以使用b.uniq
答案 1 :(得分:1)
像Photo.where(id: some_array)
这样的ActiveRecord查询产生如下SQL:
select ... from photos where id in (...)
但IN
中元素的顺序与数据库返回行的顺序无关;通常,唯一确定行顺序的是ORDER BY子句。
您可以让数据库订购与b
数组匹配的内容与CASE:
order by case id when 659 then 0 when 658 then 1 ... end
并且很容易在Ruby中构建:
Photo.where(id: b)
.order(%Q{case id #{b.map.each_with_index { |id, i| "when #{id} then #{i}" }.join(' ')} end })
我认为并不是非常漂亮,但它让数据库完成工作(如果您将更多内容链接到此查询中,这可能很重要)并且您可以轻松地隐藏Photo类中的类方法中的丑陋: / p>
def self.for_ids_in_order(ids)
where(id: ids).order(%Q{case id #{ids.map.each_with_index { |id, i| "when #{id} then #{i}" }.join(' ')} end })
end
然后说Photo.for_ids_in_order(b)
。
当然,这确实假设您知道b
数组的来源,并且您知道它包含整数。如果您不确定,那么您可以拨打connection.quote
来确保正确转义:
ids.map.each_with_index { |id, i| "when #{connection.quote(id)} then #{i}" }...
答案 2 :(得分:0)
b.map {| m |如果b数组中的ID是唯一的,则为Photo.find(m)} 。如果不 然后运行 b.uniq.map {| m | Photo.find(m)} 此代码的一个缺点是它对b数组中存在的每个元素运行查询。