Rails, ActiveRecord, идентификатор запроса в массиве int, сохраняют порядок переданного массива

Я думаю о наилучшем решении проблемы. Скажем, что у нас есть список идентификаторов модели ActiveRecord:

ids = [1, 100, 5, 30, 4, 2, 88, 44]

Затем я хотел бы сделать запрос, который выбирает всех пользователей, например, с идентификаторами из списка, но для сохранения порядка. Если я делаю

User.where(id: ids)

ответ будет списком пользователей с порядком asc по id, но я хочу, чтобы порядок был таким же, как в массиве.

Как вы думаете, что это лучшее решение здесь? Выбрать всех пользователей, а затем управлять списком объектов ActiveRecord? Возможно, есть более умный способ сделать это.

Спасибо!

Ответ 1

Что касается здесь, для postgresql,

User.where(id: ids).order("position(id::text in '#{ids.join(',')}')")

Ответ 2

Если вы используете 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])

Ответ 3

меньше учитывайте MySQL и Postgresql, , если у вас небольшой размер идентификаторов,

User.where(id: ids).sort_by { |u| ids.index(u.id) }

Ответ 4

Если вы используете 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

Ответ 5

users_by_id = User.find(ids).index_by(&:id) # Gives you a hash indexed by ID
ids.collect {|id| users_by_id[id] }

Ответ 6

Другая возможность для 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/...