我有以下关联:Artist has_many Songs
。因此,我可以通过以下方式获得艺术家的歌曲:
artist.songs
但是,我想只获得歌曲'体裁:
artist.songs.pluck(:genre)
但是,这种类型可能会在结果中出现多次;我只想获得独特的流派价值观。不幸的是,pluck
在这里没有任何帮助,因为它返回一个数组,并且在其上调用uniq
不会调整ActiveRecord查询,但是普通Array#uniq
我可以这样做:
artist.songs.select(:genre).uniq.pluck(:genre)
但我觉得必须有更好的方法。
P.S。:从一些最小的基准测试来看,pluck + Array#uniq
似乎比select + uniq + pluck
快一点。
答案 0 :(得分:5)
如果使用艺术家的songs
关联,您可以在select distinct
上genre
,然后将结果映射到只返回字符串:
artist.songs.select('distinct genre').map(&:genre)
# or...
artist.songs.select(:genre).uniq.map(&:genre) # uniq or distinct work
结果查询:
(0.2ms) SELECT distinct genre FROM "songs" WHERE "songs"."artist_id" = ? [["artist_id", 1]]
如果在缩小到艺术家时直接调用Song模型,您也可以使用uniq:
Song.where(artist: artist).uniq.pluck(:genre)
结果查询:
(0.2ms) SELECT DISTINCT "songs"."genre" FROM "songs" WHERE "songs"."artist_id" = 1
两者都是同等有效的,并且在SQL中执行唯一性操作,而不是在Ruby中。
答案 1 :(得分:1)
artist.songs.pluck('DISTINCT genre')
我仍在寻找更好的方法。我觉得这比select(:col).uniq.pluck(:col)
答案 2 :(得分:1)
请注意,从Rails 5开始,Relation#uniq
is deprecated; you should use Relation#distinct
instead。
我最近自己遇到了同样的问题。理想情况下,我希望以下代码可以工作 - 但它不会生成SQL来仅获取不同的值:
Song.where(artist: artist).distinct.pluck(:genre)
但是,作为一种解决方法,您可以改为:
SELECT DISTINCT "songs"."genre" FROM "songs" WHERE "songs"."artist_id" = 123
这将生成以下SQL:
class Artist < ApplicationRecord
def genres
Song.where(artist: self).distinct.pluck(:genre)
end
end
为方便起见,您还可以考虑将其添加为模型方法,例如:
Array#map
这实现了最佳性能,因为查询完全在SQL中 - 没有使用诸如Array#uniq
或<div ng-repeat="item in probability">
<div ng-class="(1-item.prob.p)>=0.5 ? 'yellowClass':'redClass'">{{1-item.prob.p}} </div>
之类的ruby操作。
答案 3 :(得分:0)
Model.uniq.pluck(:genre)
这会生成SQl查询SELECT DISTINCT
,而不是再次向数组查询.uniq。
答案 4 :(得分:0)
这是其他答案的补充。如果要根据特定列选择唯一行,也可以使用
artist.pluck('distinct on (col1) col1, col2, col3')
基本上是
select distinct on (col1) col1, col2, col3 from artist
你也可以选择
来做到这一点 artist.select('distinct on (col1) col1, col2, col3')
pluck给出数组值,其中select给出了记录数组。