Rails: pilih nilai unik dari kolom


238

Saya sudah memiliki solusi yang berfungsi, tetapi saya benar-benar ingin tahu mengapa ini tidak berhasil:

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

Itu memilih, tetapi tidak mencetak nilai unik, itu mencetak semua nilai, termasuk duplikat. Dan itu ada di dokumentasi: http://guides.rubyonrails.org/active_record_querying.html#seleksi-specific-fields


Jawaban:


449
Model.select(:rating)

Hasil dari ini adalah kumpulan Modelbenda. Bukan peringkat biasa. Dan dari uniqsudut pandang, mereka sangat berbeda. Anda bisa menggunakan ini:

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

atau ini (paling efisien)

Model.uniq.pluck(:rating)

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

Memperbarui

Rupanya, pada rail 5.0.0.1, itu hanya berfungsi pada permintaan "tingkat atas", seperti di atas. Tidak berfungsi pada proksi koleksi (hubungan "has_many", misalnya).

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

Dalam hal ini, hapus duplikat setelah kueri

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

Saya melakukan: grup (: peringkat) .collect {| r | r.rating} Karena peta == kumpulkan, di mana saya bisa membaca sintaks yang Anda gunakan (&: rating)? Saya tidak melihat ini dalam dokumentasi Ruby.
alexandrecosta

@ user1261084: lihat Simbol # to_proc untuk memahami .map (&: rating). PragDave menjelaskan
dbenhur

63
Perlu dicatat bahwa Model.uniq.pluck(:rating)ini adalah cara paling efisien untuk melakukan ini - ini menghasilkan SQL yang menggunakan SELECT DISTINCTdaripada menerapkan .uniqke array
Mikey

23
Dalam Rails 5, Model.uniq.pluck(:rating)akanModel.distinct.pluck(:rating)
neurodinamik

2
Jika Anda ingin memilih nilai unik dari hubungan has_many, Anda selalu dapat melakukannyaModel.related_records.group(:some_column).pluck(:some_column)
Krzysztof Karski

92

Jika Anda akan menggunakan Model.select, maka sebaiknya Anda gunakan saja DISTINCT, karena hanya akan mengembalikan nilai-nilai unik. Ini lebih baik karena itu berarti mengembalikan lebih sedikit baris dan harus sedikit lebih cepat daripada mengembalikan sejumlah baris dan kemudian memberi tahu Rails untuk memilih nilai-nilai unik.

Model.select('DISTINCT rating')

Tentu saja, ini disediakan database Anda memahami DISTINCTkata kunci, dan sebagian besar harus.


6
Model.select("DISTINCT rating").map(&:rating)untuk mendapatkan berbagai peringkat saja.
Kris

Bagus untuk mereka yang menggunakan aplikasi lama menggunakan Rails 2.3
Mikey

3
Ya .. ini bekerja fantastis - namun, tetapi hanya mengembalikan atribut DISTINCT. Bagaimana Anda bisa mengembalikan seluruh objek Model selama itu berbeda? Sehingga Anda akan memiliki akses ke semua atribut dalam model dalam kasus di mana atribut itu unik.
zero_cool

@Jackson_Sandland Jika Anda menginginkan objek Model, itu harus dipakai dari catatan di tabel. Tapi Anda tidak memilih catatan hanya nilai unik (dari apa yang mungkin beberapa catatan).
Benissimo

69

Ini juga berfungsi.

Model.pluck("DISTINCT rating")

Saya percaya pluck adalah Ruby 1.9.x dan lebih tinggi. Siapa pun yang menggunakan versi sebelumnya tidak akan memilikinya. Jika Anda berada di 1.9x dan di atas, dokumen ruby ​​mengatakan ini juga berfungsi: Model.uniq.pluck (: rating)
kakubei

6
pluckadalah metode Rails> 3.2 murni yang tidak memiliki ketergantungan pada Ruby 1.9.x Lihat apidock.com/rails/v3.2.1/ActiveRecord/Calculations/pluck
Daniel Rikowski

34

Jika Anda ingin juga memilih bidang tambahan:

Model.select('DISTINCT ON (models.ratings) models.ratings, models.id').map { |m| [m.id, m.ratings] }

1
select extra fields<3 <3
cappie013

27
Model.uniq.pluck(:rating)

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

Ini memiliki keuntungan karena tidak menggunakan string sql dan tidak membuat model instantiating


3
Ini melempar kesalahan dengan Rails 5.1 / AR 5.1 => metode yang tidak ditentukan `uniq '
Graham Slick

24
Model.select(:rating).uniq

Kode ini berfungsi sebagai 'DISTINCT' (bukan sebagai Array # uniq) sejak rails 3.2


5
Model.select(:rating).distinct

2
Ini adalah satu-satunya jawaban yang benar secara resmi yang juga sangat efisien. Meskipun, menambahkan .pluck(:rating)pada akhirnya akan membuatnya persis seperti yang diminta OP.
Sheharyar

5

Jika saya langsung ke jalan maka:

Permintaan saat ini

Model.select(:rating)

mengembalikan array objek dan Anda telah menulis kueri

Model.select(:rating).uniq

uniq diterapkan pada array objek dan setiap objek memiliki id unik. uniq melakukan tugasnya dengan benar karena setiap objek dalam array adalah uniq.

Ada banyak cara untuk memilih peringkat yang berbeda:

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

atau

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

atau

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

atau

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

Satu hal lagi, permintaan pertama dan kedua: cari data berbeda dengan query SQL.

Kueri ini akan dianggap "london" dan "london" yang sama artinya akan diabaikan ke ruang angkasa, itu sebabnya ia akan memilih 'london' satu kali dalam hasil permintaan Anda.

Kueri ketiga dan seterusnya:

menemukan data dengan query SQL dan untuk data yang berbeda diterapkan ruby ​​uniq mehtod. kueri ini akan dianggap "london" dan "london" berbeda, karena itu ia akan memilih 'london' dan 'london' di hasil kueri Anda.

lebih suka gambar terlampir untuk lebih memahami dan melihat "Tur / Menunggu RFP".

masukkan deskripsi gambar di sini


6
map& collectalias untuk metode yang sama, tidak perlu memberikan contoh untuk keduanya.
Adam Lassek

4

Beberapa jawaban tidak memperhitungkan OP menginginkan array nilai

Jawaban lain tidak berfungsi dengan baik jika Model Anda memiliki ribuan catatan

Yang mengatakan, saya pikir jawaban yang bagus adalah:

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

Karena, pertama-tama Anda menghasilkan larik Model (dengan ukuran yang berkurang karena pilih), kemudian Anda mengekstrak satu-satunya atribut yang dimiliki oleh model yang dipilih (peringkat)


3

Jika ada yang mencari yang sama dengan Mongoid, itu

Model.distinct(:rating)

yang ini tidak berfungsi sekarang, sekarang mengembalikan banyak.
EUPHORAY

tidak kembali berbeda
dowi

2

Cara lain untuk mengumpulkan kolom uniq dengan sql:

Model.group(:rating).pluck(:rating)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.