Rails:列から一意の値を選択する


238

私はすでに実用的な解決策を持っていますが、これがうまくいかない理由を本当に知りたいです:

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

一意の値を選択しますが、印刷はしません。重複を含むすべての値を印刷します。そしてそれはドキュメントにあります:http : //guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields


回答:


449
Model.select(:rating)

この結果は、Modelオブジェクトのコレクションです。単純な評価ではありません。とuniqの観点から、それらは完全に異なります。あなたはこれを使うことができます:

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

またはこれ(最も効率的)

Model.uniq.pluck(:rating)

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

更新

どうやら、rails 5.0.0.1以降では、上記のように「トップレベル」のクエリでのみ機能します。コレクションプロキシ(たとえば、 "has_many"リレーション)では機能しません。

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

この場合、クエリの後に重複排除します

user.addresses.pluck(:city).uniq # => ['Moscow']

私はしました:group(:rating).collect {| r | r.rating} map == collectなので、使用したこのシンタックス(&:rating)はどこで読むことができますか?Rubyのドキュメントにはこれはありません。
alexandrecosta 2012年

@ user1261084:.map(&:rating)を理解するには、Symbol#to_procを参照してください。PragDaveの説明
dbenhur

63
これModel.uniq.pluck(:rating)が最も効率的な方法であることに注意してください。これは、配列にSELECT DISTINCT適用するのではなく使用するSQLを生成します.uniq
Mikey

23
Rails 5では、次のModel.uniq.pluck(:rating)ようになりますModel.distinct.pluck(:rating)
ニューロダイナミック

2
has_many関係から一意の値を選択する場合は、いつでも行うことができますModel.related_records.group(:some_column).pluck(:some_column)
Krzysztof Karski

92

を使用する場合は、一意の値のみを返すModel.selectためDISTINCT、を使用することもできます。これは、返す行が少なく、複数の行を返し、Railsに一意の値を選択するように指示するよりもわずかに高速であることを意味するため、より優れています。

Model.select('DISTINCT rating')

もちろん、これはあなたのデータベースがDISTINCTキーワードを理解していれば提供され、ほとんどの人はそうです。


6
Model.select("DISTINCT rating").map(&:rating)評価のみの配列を取得します。
Kris

Rails 2.3を使用するレガシーアプリを使用しているユーザー
Mikey

3
はい..これは素晴らしい働きをしますが、DISTINCT属性のみを返します。Modelオブジェクト全体が異なる限り、どのようにして返すことができますか?そのため、属性が一意であるインスタンスでは、モデル内のすべての属性にアクセスできます。
zero_cool 2014年

@Jackson_Sandland Modelオブジェクトが必要な場合は、テーブルのレコードからインスタンス化する必要があります。ただし、(複数のレコードの可能性があるものから)一意の値だけを選択するわけではありません。
Benissimo、2015年

69

これも機能します。

Model.pluck("DISTINCT rating")

pluckはRuby 1.9.x以降だと思います。以前のバージョンを使用している人は誰も持っていません。:Model.uniq.pluck(:評価)あなたが1.9倍にし、上にある場合は、ルビーのドキュメントは、これはまた、作品と言う
kakubei

6
pluckあるルビーに依存しません純粋なRailsの> 3.2方法は参照1.9.x apidock.com/rails/v3.2.1/ActiveRecord/Calculations/pluck
ダニエルRikowskiを


27
Model.uniq.pluck(:rating)

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

これには、SQL文字列を使用せず、モデルをインスタンス化しないという利点があります。


3
これはRails 5.1 / AR 5.1 => undefined method `uniq 'でエラーをスローします
Graham Slick

24
Model.select(:rating).uniq

このコードは、rails 3.2以降、(Array#uniqではなく)「DISTINCT」として機能します


5
Model.select(:rating).distinct

2
これは公式に正解で唯一、これも非常に効率的です。ただし、.pluck(:rating)最後に追加すると、OPが要求したとおりになります。
Sheharyar

5

私が道に行くなら:

現在のクエリ

Model.select(:rating)

オブジェクトの配列を返し、クエリを記述しました

Model.select(:rating).uniq

uniqはオブジェクトの配列に適用され、各オブジェクトには一意のIDがあります。配列内の各オブジェクトはuniqであるため、uniqは正しく機能します。

異なる評価を選択するには多くの方法があります。

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

または

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

または

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

または

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

もう1つ、1番目と2番目のクエリ:SQLクエリで個別のデータを検索します。

これらのクエリは "london"と "london"を同じと見なし、スペースを無視することを意味します。そのため、クエリ結果で「london」が1回選択されます。

3番目と4番目のクエリ:

SQLクエリでデータを検索し、ルビーユニコードメソッドを適用した個別のデータを検索します。これらのクエリは "london"と "london"が異なると見なされるため、クエリ結果で「london」と「london」の両方が選択されます。

詳細については添付の画像をご覧になり、「ツアー/ RFP待ち」をご覧ください。

ここに画像の説明を入力してください


6
mapcollectは同じメソッドのエイリアスです。両方の例を提供する必要はありません。
Adam Lassek 14

4

OPが値の配列を必要としていることを考慮に入れていない回答もあります

モデルに数千のレコードがある場合、他の回答はうまく機能しません

そうは言っても、良い答えは次のとおりです。

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

最初に、モデルの配列を生成します(選択によりサイズが縮小されます)。次に、選択されたモデルが持つ属性(評価)のみを抽出します。


3

誰かがモンゴイドで同じものを探しているなら、それは

Model.distinct(:rating)

これは今は機能せず、複数を返すようになりました。
EUPHORAY 2018

明確な結果は返されません
dowi

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.