web-dev-qa-db-fra.com

Comment obtenir une association polymorphe distincte

J'essaie d'obtenir une liste de relations polymorphes sans avoir de doublons.

J'ai une table StoreViews avec un champ polymorphe appelé viewable (il y a donc une colonne viewable_id et viewable_type dans ma table). Maintenant, je veux afficher des vues avec chaque relation polymorphe apparaissant une seule fois, sans doublons.

@views = StoreView.
    .distinct(:viewable_id)
    .distinct(:viewable_type)
    .order("created_at DESC")
    .limit(10)

Ainsi, s'il existe deux enregistrements dans StoreViews, tous deux avec la même relation visible, @views ne doit renvoyer que le plus récent. Cependant, ce n'est pas le cas.

6
NathanB

Les éléments ORDER BY doivent apparaître dans la liste de sélection si SELECT DISTINCT est spécifié. Il existe plusieurs façons de contourner ce problème

Dans cet exemple, utiliser une fonction d'agrégat devrait fonctionner:

@views = StoreView
           .select('DISTINCT viewable_type, viewable_id, MAX(created_at)')
           .group(:viewable_type, :viewable_id)
           .order('MAX(created_at) DESC')
           .limit(10)
6
spickermann

distinct accepte uniquement un booléen en tant que paramètre permettant de spécifier si les enregistrements doivent être uniques ou non. Donc, distinct(:viewable_id) est équivalent à distinct(true) et ne fait pas ce que vous voulez. Au lieu d'utiliser distinct, vous devez utiliser group , qui renvoie un tableau avec des enregistrements distincts en fonction de l'attribut de groupe. Pour renvoyer le plus récent, à part la commande (avec order ) par created_at, vous devez ajouter les champs dans group:

@views = StoreView
         .order(viewable_id: :desc, viewable_type: :desc, created_at: :desc)
         .group(:viewable_id, :viewable_type)

Si vous avez besoin que les enregistrements retournés soient classés par created_at, vous devez ajouter ceci.

ActiveRecord distinct:

https://apidock.com/Rails/ActiveRecord/QueryMethods/distinct

Spécifie si les enregistrements doivent être uniques ou non. Par exemple:

User.select(:name)
# => Might return two records with the same name

User.select(:name).distinct
# => Returns 1 record per distinct name

Que dis-tu de ça:

@views = StoreView
    .select(:viewable_id, :viewable_type)
    .distinct
    .order("created_at DESC")
    .limit(10)

Vous pouvez aussi essayer 

@views = StoreView
    .select('DISTINCT `viewable_id`, `viewable_type`')
    .order("created_at DESC")
    .limit(10)
0
oren