So erhalten Sie die Werte einer einzelnen Spalte in ein Array

79

Im Moment mache ich so etwas, um eine einzelne Datenspalte auszuwählen:

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

Wenn ich sie dann an eine Methode übergebe, möchte ich, dass meine Methode agnostisch bleibt und jetzt hash.point aus meiner Methode heraus aufrufen muss. Wie kann ich dies schnell in ein Array konvertieren und den Datensatz an meine Methode übergeben, oder gibt es einen besseren Weg?

Franklin Stine
quelle

Antworten:

189

In Rails 3.2 gibt es eine zupfen Methode für diese

Genau wie dieser:

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)

Unterschied zwischen einzigartig und verschieden

Alony
quelle
Wie kann ein Array die Reihenfolge eines Abfrageergebnisses mit Zupfen erben?
Franklin Stine
3
Post.order (: score) .pluck (: score) ist die Lösung. Vielen Dank.
Franklin Stine
6
Zum Zupfen von IDs gibt es eine spezielle Methode : Person.ids.
Schock_one
Schauen Sie sich auch Ernie Millers Juwel Valium github.com/ernie/valium an, besonders wenn Sie auf einer älteren Schiene sind oder mehrere Spalten möchten
James Daniels
Ab Rails 5.0 wird jetzt empfohlen, distinctanstelle von uniq: soPerson.distinct.pluck(:role)
David
15

Sie sollten die pluckMethode wie von @alony vorgeschlagen verwenden. Wenn Sie vor Rails 3.2 nicht weiterkommen, können Sie die ActiveRecord- selectMethode zusammen mit Array#mapfolgenden Methoden verwenden :

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

vor Ruby 1.9 müssten Sie dies jedoch tun .map{|x| x.title}, da Symbol#to_proc(Aliasing durch den unären &Operator) in früheren Versionen von Ruby nicht definiert ist.

Patrick Oscity
quelle
Vielen Dank. Ich habe gesehen, dass Sie die neue Zupfmethode kommentiert haben. Kannst du das auch so machen?
Franklin Stine
Ja, wenn Sie die Antwort von @ alony sorgfältig lesen, werden Sie feststellen, dass sie bereits ein Beispiel beigefügt hat, das dies tut.
Patrick Oscity
5

Wenn Sie die Definition von select_values ​​sehen, verwenden Sie 'map (&: field_name)'.

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

Die allgemeine und allgemeine Rails-Methode zum Sammeln aller Feldwerte im Array lautet wie folgt:

points = Post.all(:select => 'point').map(&:point)
Vik
quelle
Guter Punkt. Vielen Dank. Dies funktioniert hervorragend und ermöglicht es mir, im Gegensatz zum Post.select-Beispiel weiterhin die Reihenfolge und andere Dinge auf die Abfrage anzuwenden.
Franklin Stine
Ich stimme dir nicht zu, @franklinstine: Post.select(:point).limit(1)führt aus, SELECT point FROM "posts" LIMIT 1während Post.all(:select => :point).limit(1)a NoMethodError. Bitte korrigieren Sie mich, falls ich falsch liege.
Patrick Oscity
Ich stimme Ihren Kommentaren zu. Aber ich bekomme nicht, wo in dem Beitrag erwähnt wird, um zu verwenden: Post.all (: select =>: point) .limit (1) Natürlich wird es Fehler "undefinierte Methode` limit '"geben
Vik
@franklinstine sagte, dass er Ihre Methode bevorzugt, weil er andere Aussagen danach verketten könnte, ich wollte nur
klarstellen
Ja @padde du hast falsch gefolgert. Ich sagte, Sie können weiterhin Order- und andere Abfrageanweisungen anwenden, z. B.: Post.all (: select => 'score' ,: order => 'score ASC'). Map (&: score).
Franklin Stine
2
points = Post.all.collect {|p| p.point}
Rajibchowdhury
quelle
2
Dies funktioniert, aber Sie wählen alle Felder aus der Datenbank aus und filtern das Ergebnis in Ruby, während die selectAnweisung nur die angegebenen Spalten abruft.
Patrick Oscity