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?

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


¿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.


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)

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}

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.