51 votes

Trouver les enregistrements du modèle par ID dans l'ordre où le tableau d'ID a été donné.

J'ai une requête pour obtenir les ID des personnes dans un ordre particulier, par exemple : ids = [1, 3, 5, 9, 6, 2]

Je veux ensuite récupérer ces personnes par Person.find(ids)

Mais ils sont toujours récupérés dans l'ordre numérique, je le sais par expérience :

people = Person.find(ids).map(&:id)
 => [1, 2, 3, 5, 6, 9]

Comment puis-je exécuter cette requête de manière à ce que l'ordre soit le même que celui du tableau des identifiants ?

J'ai rendu cette tâche plus difficile car je ne voulais exécuter la requête pour récupérer les personnes qu'une seule fois, à partir des ID donnés. Il est donc hors de question d'effectuer plusieurs requêtes.

J'ai essayé quelque chose comme :

ids.each do |i|
  person = people.where('id = ?', i)

Mais je ne pense pas que cela fonctionne.

0voto

user3033467 Points 360

Cette solution simple coûte moins cher qu'une adhésion sur les valeurs :

order_query = <<-SQL
  CASE persons.id 
    #{ids.map.with_index { |id, index| "WHEN #{id} THEN #{index}" } .join(' ')}
    ELSE #{ids.length}
  END
SQL
Person.where(id: ids).order(order_query)

0voto

Muhammad Aamir Points 48

Pour obtenir les identifiants des personnes dans un ordre particulier, disons : ids = [1, 3, 5, 9, 6, 2]

Dans les anciennes versions de rails, find et where récupèrent les données dans l'ordre numérique, mais rails 5 récupère les données dans l'ordre dans lequel vous les interrogez.

Note : trouver préserver l'ordre et où ne pas le préserver.

Person.find(ids).map(&:id)
=> [1, 3, 5, 9, 6, 2]

Person.where(id: ids).map(&:id)
=> [1, 2, 3, 5, 6, 9] 

Mais ils sont toujours récupérés dans l'ordre numérique, je le sais par expérience :

0voto

arooaroo Points 1588

J'ai essayé les réponses recommandant la méthode FIELD sur Rails6 mais je rencontrais des erreurs. Cependant, j'ai découvert que tout ce que l'on doit faire est d'envelopper le sql dans Arel.sql() .

# Make sure it's a known-safe values.
user_ids = [3, 2, 1]
# Before 
users = User.where(id: user_ids).order("FIELD(id, 2, 3, 1)")
# With warning.

# After 
users = User.where(id: user_ids).order(Arel.sql("FIELD(id, 2, 3, 1)"))
# No warning

[1] https://medium.com/@mitsun.chieh/activerecord-relation-with-raw-sql-argument-returns-a-warning-exception-raising-8999f1b9898a

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X