1
votes

Regroupement et classement à l'aide de l'interface de requête ActiveRecord

J'ai un modèle, ConnectedUser , qui appartient à 2 autres modèles User et Station .

C'est un modèle simple avec juste ces relations et un booléen active .

Les résultats de la requête que je vise ne seraient que chaque enregistrement ConnectedUser le plus récent pour chaque User (où la Station est un identifiant spécifique).

Par exemple, si ma table ConnectedUser ressemblait à ceci. .

ConnectedUser.where(station: station).select(:user_id).group(:user_id).order(:created_at)

Et la station était celle avec l'identifiant 1 alors j'aimerais que la requête retourne ...

[
<ConnectedUser id: 1, user_id: 1, station_id: 1, active: true, created_at: "2019-06-20">,
<ConnectedUser id: 5, user_id: 2, station_id: 1, active: false, created_at: "2019-06-21">
]

Pour y parvenir, j'ai essayé d'utiliser group pour et order

+----+---------+------------+--------+------------+
| id | user_id | station_id | active | created_at |
+----+---------+------------+--------+------------+
|  1 |       1 |          1 | true   | 20 June    |
|  2 |       1 |          1 | false  | 19 June    |
|  3 |       1 |          2 | false  | 20 June    |
|  4 |       2 |          1 | false  | 18 June    |
|  5 |       2 |          1 | false  | 21 June    |
+----+---------+------------+--------+------------+

mais j'ai continué à recevoir des erreurs comme ceci:

ActiveRecord :: StatementInvalid (PG :: GroupingError: ERROR: colonne "connected_users.created_at" doit apparaître dans la clause GROUP BY ou être utilisé dans une fonction d'agrégation)

Je ne parviens pas à obtenir l'identifiant spécifique de ConnectedUser , alors j'ai l'impression que je manque de connaissances importantes sur la manière de travailler avec group et d'agréger les résultats .

Est-ce possible dans une seule requête ActiveRecord?

Merci beaucoup.


1 commentaires

Toutes mes excuses, cela ne devrait pas changer, j'ai édité pour corriger cela.


3 Réponses :


1
votes

Dans Postgres, si vous voulez la version la plus récente pour chaque utilisateur / poste, je recommanderais distinct sur :

select distinct on (station_id, user_id) cu.*
from ConnectedUser cu
order by station_id, user_id, created_at desc;


1 commentaires

Merci, j'aimerais utiliser la requête ActiveRecord si possible afin de pouvoir passer la station via des paramètres.



1
votes

Vous devez utiliser DISTINCT ON au lieu de GROUP . Voici comment vous pouvez le faire dans Rails:

ConnectedUser.select("DISTINCT ON (station_id, user_id) *")
             .where(station_id: params[:station_id])
             .order(created_at: :desc)

Bien sûr, avec params [: station_id] c'est ce que vous voulez filtrer


2 commentaires

Merci d'essayer que ConnectedUser.select ("DISTINCT ON (station_id, user_id)"). Where (station: station) .order (created_at:: desc) me donne cette erreur cependant ... < code> ActiveRecord :: StatementInvalid (PG :: SyntaxError: ERROR: erreur de syntaxe à ou près de "FROM") LINE 1: SELECT DISTINCT ON (station_id, user_id) FROM "connected_use ...


Ouais, il semble que j'ai oublié le caractère * dans l'instruction select. Veuillez consulter ma réponse mise à jour et voir si cela fonctionne maintenant



0
votes

Probablement, cela résoudrait le problème

ConnectedUser.where (active: true) .order (user_id:: desc) .uniq (&: user_id)

order est utilisé pour trier le champ user_id dans DESC

sur cette solution, j'utilise uniq , qui est une solution de tableau, et je ne sélectionnerai que le plus récent user_id

modifier:

J'avais tort, uniq ne fonctionnait pas comme prévu, mais en testant ici, je découvre que:

ConnectedUser.where (active: true) .order (created_at:: desc) .group (: user_id)

ressemble beaucoup au vôtre, mais, lorsque vous utilisez select, il ne sélectionne que le champ user_id, donc vous ne pouvez pas commander par created_at

Devrait fonctionner


4 commentaires

Merci, utiliser uniq semble intéressant mais je pense que uniq est désormais obsolète au profit de distinct . En l'essayant, il ne semble pas non plus renvoyer les enregistrements les plus récents, mais la commande par created_at n'a pas semblé aider.


Bonjour, avec la version modifiée, je reçois à nouveau l'erreur familière que j'ai essayé de résoudre: (PG :: GroupingError: ERROR: la colonne "connected_users.id" doit apparaître dans la clause GROUP BY ou être utilisé dans une fonction d'agrégation) merci d'avoir essayé.


@Chris, et si vous essayez de mettre id dans le groupe, comme group (: id,: user_id) ?


Oui, j'ai essayé cette approche et ses variantes, sans aucune chance. Merci encore.