Rieles: seleccione valores únicos de una columna

238

Ya tengo una solución que funciona, pero realmente me gustaría saber por qué esto no funciona:

ratings = Model.select(:rating).uniq
ratings.each { |r| puts r.rating }

Selecciona, pero no imprime valores únicos, imprime todos los valores, incluidos los duplicados. Y está en la documentación: http://guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields

alexandrecosta
fuente
2
Otro ejemplo con uniq stackoverflow.com/questions/8369812/…
manish nautiyal

Respuestas:

449
Model.select(:rating)

El resultado de esto es una colección de Modelobjetos. No clasificaciones simples. Y desde uniqel punto de vista, son completamente diferentes. Puedes usar esto:

Model.select(:rating).map(&:rating).uniq

o esto (más eficiente)

Model.uniq.pluck(:rating)

# rails 5+
Model.distinct.pluck(:rating)

Actualizar

Aparentemente, a partir de rails 5.0.0.1, solo funciona en consultas de "nivel superior", como las anteriores. No funciona en proxies de colección (relaciones "has_many", por ejemplo).

Address.distinct.pluck(:city) # => ['Moscow']
user.addresses.distinct.pluck(:city) # => ['Moscow', 'Moscow', 'Moscow']

En este caso, deduplicar después de la consulta

user.addresses.pluck(:city).uniq # => ['Moscow']
Sergio Tulentsev
fuente
Hice un: group (: rating) .collect {| r | r.rating} Dado que map == collect, ¿dónde puedo leer sobre esta sintaxis que utilizó (&: rating)? No veo esto en la documentación de Ruby.
alexandrecosta
@ user1261084: vea Symbol # to_proc para comprender .map (&: rating). PragDave explica
dbenhur
63
Vale la pena señalar que Model.uniq.pluck(:rating)es la forma más eficiente de hacer esto: esto genera SQL que usa en SELECT DISTINCTlugar de aplicar .uniqa una matriz
Mikey
23
En Rails 5, Model.uniq.pluck(:rating)seráModel.distinct.pluck(:rating)
neurodinámico
2
Si desea seleccionar valores únicos de la relación has_many, siempre puede hacerloModel.related_records.group(:some_column).pluck(:some_column)
Krzysztof Karski
92

Si va a usar Model.select, entonces también podría usar DISTINCT, ya que devolverá solo los valores únicos. Esto es mejor porque significa que devuelve menos filas y debería ser un poco más rápido que devolver varias filas y luego decirle a Rails que elija los valores únicos.

Model.select('DISTINCT rating')

Por supuesto, esto se proporciona si su base de datos comprende la DISTINCTpalabra clave, y la mayoría debería.

kakubei
fuente
66
Model.select("DISTINCT rating").map(&:rating)para obtener una variedad de solo las calificaciones.
Kris
Ideal para aquellos con aplicaciones heredadas que usan Rails 2.3
Mikey
3
Sí, esto funciona fantástico, sin embargo, pero solo devuelve el atributo DISTINCT. ¿Cómo puede devolver todo el objeto Modelo siempre que sea distinto? Para que tenga acceso a todos los atributos en el modelo en instancias donde el atributo es único.
zero_cool
@Jackson_Sandland Si desea un objeto Modelo, deberá crear una instancia de un registro en la tabla. Pero no está seleccionando un registro solo un valor único (de lo que puede ser múltiples registros).
Benissimo
69

Esto tambien funciona.

Model.pluck("DISTINCT rating")
Nat
fuente
Creo que Pluck es Ruby 1.9.xy superior. Cualquiera que use una versión anterior no la tendrá. Si está en 1.9xy superior, los documentos de ruby ​​dicen que esto también funciona: Model.uniq.pluck (: rating)
kakubei
66
pluckes un método puro de Rails> 3.2 que no depende de Ruby 1.9.x Ver apidock.com/rails/v3.2.1/ActiveRecord/Calculations/pluck
Daniel Rikowski
34

Si también desea seleccionar campos adicionales:

Model.select('DISTINCT ON (models.ratings) models.ratings, models.id').map { |m| [m.id, m.ratings] }
Marcin Nowicki
fuente
1
select extra fields<3 <3
cappie013
27
Model.uniq.pluck(:rating)

# SELECT DISTINCT "models"."rating" FROM "models"

Esto tiene las ventajas de no usar cadenas sql y no crear modelos de instancia

Cameron Martin
fuente
3
Esto arroja un error con Rails 5.1 / AR 5.1 => método indefinido `uniq '
Graham Slick
24
Model.select(:rating).uniq

Este código funciona como 'DISTINCT' (no como Array # uniq) ya que rails 3.2

kuboon
fuente
5
Model.select(:rating).distinct
hassan_i
fuente
2
Esta es la única respuesta oficialmente correcta que también es súper eficiente. Sin .pluck(:rating)embargo , agregar al final hará que sea exactamente lo que solicitó el OP.
Sheharyar
5

Si voy directo al camino, entonces:

Consulta actual

Model.select(:rating)

está devolviendo una matriz de objetos y ha escrito consulta

Model.select(:rating).uniq

uniq se aplica en una matriz de objetos y cada objeto tiene una identificación única. uniq está realizando su trabajo correctamente porque cada objeto en la matriz es uniq.

Hay muchas formas de seleccionar una calificación distinta:

Model.select('distinct rating').map(&:rating)

o

Model.select('distinct rating').collect(&:rating)

o

Model.select(:rating).map(&:rating).uniq

o

Model.select(:name).collect(&:rating).uniq

Una cosa más, primera y segunda consulta: encuentre datos distintos por consulta SQL.

Estas consultas se considerarán "londres" y "londres" lo mismo significa que descuidará el espacio, es por eso que seleccionará 'londres' una vez en el resultado de su consulta.

Tercera y cuarta consulta:

buscar datos por consulta SQL y para datos distintos aplicados ruby ​​uniq mehtod. estas consultas se considerarán "londres" y "londres" diferentes, por eso seleccionará 'londres' y 'londres' en el resultado de su consulta.

por favor, prefiera la imagen adjunta para una mejor comprensión y eche un vistazo a "Recorrido / En espera de RFP".

ingrese la descripción de la imagen aquí

uma
fuente
66
map& collectson alias para el mismo método, no hay necesidad de proporcionar ejemplos para ambos.
Adam Lassek
4

Algunas respuestas no tienen en cuenta que el OP quiere una matriz de valores

Otras respuestas no funcionan bien si su modelo tiene miles de registros

Dicho esto, creo que una buena respuesta es:

    Model.uniq.select(:ratings).map(&:ratings)
    => "SELECT DISTINCT ratings FROM `models` " 

Porque, primero genera una matriz de Modelo (con un tamaño disminuido debido a la selección), luego extrae el único atributo que tienen esos modelos seleccionados (calificaciones)

Fernando Fabreti
fuente
3

Si alguien está buscando lo mismo con Mongoid, eso es

Model.distinct(:rating)
Vassilis
fuente
este no funciona ahora, ahora devuelve múltiplos.
EUPHORAY
no vuelve distinta
dowi
2

Otra forma de recopilar columnas uniq con sql:

Model.group(:rating).pluck(:rating)
Slava Zharkov
fuente