Cómo obtener los valores de una sola columna en una matriz

80

Ahora mismo estoy haciendo algo como esto para seleccionar una sola columna de datos:

points = Post.find_by_sql("select point from posts")

Luego, pasándolos a un método, me gustaría que mi método permaneciera agnóstico y ahora tengo que llamar a hash.point desde dentro de mi método. ¿Cómo puedo convertir esto rápidamente en una matriz y pasar el conjunto de datos a mi método, o hay una mejor manera?

franklin stine
fuente

Respuestas:

190

En Rails 3.2 hay un método de extracción para esto

Así:

Person.pluck(:id) # SELECT people.id FROM people
Person.pluck(:role).uniq # unique roles from array of people
Person.distinct.pluck(:role) # SELECT DISTINCT role FROM people SQL
Person.where(:confirmed => true).limit(5).pluck(:id)

Diferencia entre uniq y distinto

solo
fuente
¿Cómo puede una matriz heredar el orden de los resultados de una consulta con pluck?
franklin stine
3
Post.order (: score) .pluck (: score) es la solución. Gracias.
franklin stine
6
Para arrancar las identificaciones hay un método especial: Person.ids.
shock_one
También mire la joya de Ernie Miller, Valium github.com/ernie/valium, especialmente si está en un Rails más antiguo o si desea varias columnas
James Daniels
A partir de Rails 5.0, ahora se recomienda usar en distinctlugar de uniq: entoncesPerson.distinct.pluck(:role)
David
15

Deberías usar el pluckmétodo como sugirió @alony. Si está atascado antes de Rails 3.2, puede usar el selectmétodo ActiveRecord junto con Array#map:

Post.select(:point).map(&:point)
#=> ["foo", "bar", "baz"] 

.map{|x| x.title}sin embargo, antes de Ruby 1.9 tendrías que hacerlo , porque Symbol#to_proc(alias por el &operador unario ) no está definido en versiones anteriores de Ruby.

Patrick Oscity
fuente
Gracias. Te vi comentar sobre el nuevo método Pluck. ¿Puedes hacer lo mismo con eso?
franklin stine
Sí, si lees la respuesta de @alony detenidamente, notarás que ella ya incluyó un ejemplo que hace esto.
Patrick Oscity
5

Si ve la definición de select_values, entonces use 'map (&: field_name)'

  def select_values(arel, name = nil)
    result = select_rows(to_sql(arel), name)
    result.map { |v| v[0] }
  end

La forma común y general de Rails para recopilar todos los valores de los campos en una matriz es como:

points = Post.all(:select => 'point').map(&:point)
Vik
fuente
Buen punto. Gracias. Esto funciona muy bien y todavía me permite aplicar orden y otras cosas a la consulta, a diferencia del ejemplo de Post.select.
franklin stine
No estoy de acuerdo contigo, @franklinstine: Post.select(:point).limit(1)realiza SELECT point FROM "posts" LIMIT 1mientras que Post.all(:select => :point).limit(1)aumenta a NoMethodError. Por favor corrígeme si estoy equivocado.
Patrick Oscity
Estoy de acuerdo con tus comentarios. Pero no obtengo la mención en la publicación para usar: Post.all (: select =>: point) .limit (1) Por supuesto, dará el error "método indefinido` límite '"
Vik
@franklinstine dijo que prefiere su método porque podría encadenar otras declaraciones después de él, solo quería dejar en claro que esto no es cierto
Patrick Oscity
Sí @padde, infieres mal. Estaba diciendo que aún puede aplicar orden y otras declaraciones de consulta como: Post.all (: select => 'score',: order => 'score ASC'). Map (&: score).
franklin stine
2
points = Post.all.collect {|p| p.point}
Rajibchowdhury
fuente
2
Esto funciona, pero selecciona todos los campos de la base de datos y luego filtra el resultado en Ruby mientras que la selectdeclaración solo recupera las columnas especificadas.
Patrick Oscity