Rails:从列中选择唯一值


238

我已经有一个可行的解决方案,但是我真的很想知道为什么这不起作用:

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

它选择但不打印唯一值,而是打印所有值,包括重复项。它在文档中:http : //guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields


Answers:


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 | 既然map == collect,那么我在哪里可以了解到您使用过的此sintax(&:rating)?我在Ruby的文档中没有看到这一点。
alexandrecosta 2012年

@ user1261084:请参阅Symbol#to_proc以了解.map(&:rating)。PragDave解释
dbenhur

63
值得注意的是,这Model.uniq.pluck(:rating)是最有效的方法-生成的SQL使用SELECT DISTINCT而不是应用.uniq到数组
Mikey 2013年

23
在Rails 5中,Model.uniq.pluck(:rating)将是Model.distinct.pluck(:rating)
神经动力学'16

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)2013年

非常适合那些使用Rails 2.3的遗留应用程序的用户
Mikey 2013年

3
是的..效果很好-但是,它只返回DISTINCT属性。只要它与众不同,如何返回整个Model对象?这样,您可以在属性唯一的实例中访问模​​型中的所有属性。
zero_cool 2014年

@Jackson_Sandland如果需要Model对象,则需要从表中的记录实例化该对象。但是,您并不是仅选择一个唯一值(可能是多个记录)来选择一条记录。
贝尼西莫2015年




24
Model.select(:rating).uniq

rails 3.2起,此代码就用作“ DISTINCT”(而不是Array#uniq)


5
Model.select(:rating).distinct

2
这是唯一超级有效的官方正确答案。虽然,最后添加.pluck(:rating)将使其完全符合OP的要求。
Sheharyar '18

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

另外,第一和第二查询:通过SQL查询查找不同的数据。

这些查询将被视为“ london”和“ london”,这意味着它将忽略空格,这就是为什么它将在查询结果中一次选择“ london”的原因。

第三和第四查询:

通过SQL查询查找数据,并针对不同的数据应用ruby uniq mehtod。这些查询将认为“ london”和“ london”不同,这就是为什么它将在查询结果中同时选择“ london”和“ london”的原因。

请更喜欢附上图片以了解更多信息,并查看“巡回/等待RFP”。

在此处输入图片说明


6
mapcollect是同一方法的别名,无需为两者提供示例。
亚当·拉瑟克

4

一些答案没有考虑到OP想要一个值数组

如果您的模型有成千上万条记录,其他答案将无法正常工作

也就是说,我认为一个不错的答案是:

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

因为,首先生成一个Model数组(由于选择而导致尺寸减小),然后提取出那些所选模型具有的唯一属性(等级)


3

如果有人在寻找与Mongoid相同的东西,那就是

Model.distinct(:rating)

这个现在不起作用,它现在返回倍数。
EUPHORAY

不会返回不同
dowi

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.