Ответ 1
Что касается здесь, для postgresql,
User.where(id: ids).order("position(id::text in '#{ids.join(',')}')")
Я думаю о наилучшем решении проблемы. Скажем, что у нас есть список идентификаторов модели ActiveRecord:
ids = [1, 100, 5, 30, 4, 2, 88, 44]
Затем я хотел бы сделать запрос, который выбирает всех пользователей, например, с идентификаторами из списка, но для сохранения порядка. Если я делаю
User.where(id: ids)
ответ будет списком пользователей с порядком asc по id, но я хочу, чтобы порядок был таким же, как в массиве.
Как вы думаете, что это лучшее решение здесь? Выбрать всех пользователей, а затем управлять списком объектов ActiveRecord? Возможно, есть более умный способ сделать это.
Спасибо!
Что касается здесь, для postgresql,
User.where(id: ids).order("position(id::text in '#{ids.join(',')}')")
Если вы используете MySQL, вы можете использовать FIELD
для упорядочения результатов:
class User < ActiveRecord::Base
def self.find_in_order(ids)
self.where(id: ids).order("FIELD(id, #{ids.join(',')})")
end
end
User.find_in_order([1, 100, 5, 30, 4, 2, 88, 44])
меньше учитывайте MySQL и Postgresql, , если у вас небольшой размер идентификаторов,
User.where(id: ids).sort_by { |u| ids.index(u.id) }
Если вы используете Postgres, вы можете использовать intarray
class User < ActiveRecord::Base
def self.find_in_order(ids)
self.where(id: ids).order("idx(array[#{ids.join(',')}], id)")
end
end
вы должны сначала запустить модуль
CREATE EXTENSION intarray
users_by_id = User.find(ids).index_by(&:id) # Gives you a hash indexed by ID
ids.collect {|id| users_by_id[id] }
Другая возможность для Postgres (9.4 или более поздняя версия):
ordered_ids = [1, 100, 5, 30, 4, 2, 88, 44]
User.joins("join unnest('{#{ordered_ids.join(',')}}'::int[]) WITH " \
"ORDINALITY t(id, ord) USING (id)").reorder('t.ord')
Обратите внимание, что порядок очень важен.
Решение на основе fooobar.com/info/61830/...