Сохранение порядка массива при использовании .where в Rails - PullRequest
1 голос
/ 09 мая 2020

Я передаю массив идентификаторов в .where в Rails, но способ его возврата не сохраняет порядок. Например, вот массив:

2.5.1 :043 > company_ids
 => [83, 79, 52, 44, 82]

Я ищу все страницы, которые имеют эти идентификаторы компании, но возвращаются в порядке этих идентификаторов компаний, которые были предоставлены. Это результат, если я попытаюсь сравнить:

2.5.1 :044 > Page.where(company_id: company_ids).pluck(:company_id)
   (1.1ms)  SELECT "pages"."company_id" FROM "pages" WHERE "pages"."company_id" IN ($1, $2, $3, $4, $5)  [["company_id", 83], ["company_id", 79], ["company_id", 52], ["company_id", 44], ["company_id", 82]]
 => [83, 82, 52, 44, 79]

Я наткнулся на эту публикацию stackoverflow ( ActiveRecord.find (array_of_ids), сохраняя порядок ), которая, кажется, предоставляет решение, но у меня это не работает. При попытке использовать Page.where(company_id: company_ids).order("field(company_id, #{company_ids.join ','})"), как предложено в сообщении stackoverflow, я получаю следующую ошибку:

2.5.1 :042 > Page.where(company_id: company_ids).order("field(company_id, #{company_ids.join ','})")
  Page Load (2.0ms)  SELECT  "pages".* FROM "pages" WHERE "pages"."company_id" IN ($1, $2, $3, $4, $5) ORDER BY field(company_id, 83,79,52,44,82) LIMIT $6  [["company_id", 83], ["company_id", 79], ["company_id", 52], ["company_id", 44], ["company_id", 82], ["LIMIT", 11]]
Traceback (most recent call last):
ActiveRecord::StatementInvalid (PG::UndefinedFunction: ERROR:  function field(bigint, integer, integer, integer, integer, integer) does not exist)
LINE 1: ...ts"."company_id" IN ($1, $2, $3, $4, $5) ORDER BY field(comp...
                                                             ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
: SELECT  "pages".* FROM "pages" WHERE "pages"."company_id" IN ($1, $2, $3, $4, $5) ORDER BY field(company_id, 83,79,52,44,82) LIMIT $6

Я просто хочу позвонить Pages.where(company_id: company_ids) и вернуть страницы в порядке company_ids это было предоставлено.

В качестве обходного пути я использую это:

company_ids = companies.order("full_name ASC").pluck(:id)
pages = []
company_ids.each {|c| pages << Page.find_by(company_id: c)}

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

1 Ответ

2 голосов
/ 09 мая 2020

Проблема в том, что вы используете функцию MySQL (поле), но СУБД, которую вы используете, - PostgreSQL.

Вы можете попробовать с position, используя строку company_id и объединенный массив идентификаторов:

Page.where(company_id: company_ids).order("position(company_id::text in '#{ids.join(',')}')")

Используйте:

Page.where(company_id: company_ids).order(Arel.sql("position(company_id::text in '#{ids.join(',')}')"))

, если вы получаете предупреждение об устаревании.

Также существует возможность использовать find, что, как указано в do c, означает . Возвращаемые записи находятся в том же порядке, что и идентификаторы, которые вы предоставляете . Хотя я не знаю, применимо ли это к вашему случаю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...