我的Company
模型有很多Disclosures
。 Disclosure
包含名为title
,pdf
和pdf_sha256
的列。
class Company < ActiveRecord::Base
has_many :disclosures
end
class Disclosure < ActiveRecord::Base
belongs_to :company
end
我想通过pdf_sha256
使其独一无二,如果pdf_sha256
为nil
则应将其视为唯一。
如果是Array
,我会这样写。
companies_with_sha256 = company.disclosures.where.not(pdf_sha256: nil).group_by(&:pdf_sha256).map do |key,values|
values.max_by{|v| v.title.length}
end
companies_without_sha256 = company.disclosures.where(pdf_sha256: nil)
companies = companies_with_sha256 + companeis_without_sha256
如何使用Rails查询获得相同的结果?
答案 0 :(得分:1)
假设您使用的是Rails 5,您可以链接.or命令来合并您的查询。
pdf_sha256_unique_disclosures = company.disclosures.where(pdf_sha256: nil).or(company.disclosures.where.not(pdf_sha256: nil))
然后你可以继续你的group_by逻辑。
但是,在上面的示例中,我并不完全确定目标是什么,但我很想知道如何使用生成的companies
变量。
如果您想拥有包含nil的唯一pdf_sha256密钥的哈希值,以及由此产生的独特披露文档,您可以尝试以下方法:
sorted_disclosures = company.disclosures.group_by(&:pdf_sha256).each_with_object({}) do |entries, hash|
hash[entries[0]] = entries[1].max_by{|v| v.title.length}
end
这应该给你一个类似于group_by的结果散列结构,其中你的密钥都是你唯一的pdf_sha256,并且该值将是与pdf_sha256匹配的最长的命名公开。
答案 1 :(得分:0)
Model.select(:rating)
这是一个Model对象数组。不是简单的评级。从uniq的角度来看,它们完全不同。你可以用这个:
Model.select(:rating).map(&:rating).uniq
或此(最有效)
Model.uniq.pluck(:rating)
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']
答案 2 :(得分:0)
为什么不:
ids = Disclosure.select(:id, :pdf_sha256).distinct.map(&:id)
Disclosure.find(ids)
id sill是不同的,因为它是主键,所以你所要做的就是映射id并按id找到Disclosures。
答案 3 :(得分:0)
您可以使用uniq方法
来实现此目的ComboBox
这将以cloumn&#34; pdf_sha256&#34;
返回您的披露记录uniq希望这对你有所帮助!干杯
答案 4 :(得分:0)
如果您需要具有不同pdf_sha256
的关系,而您不需要明确的条件,则可以使用group -
scope :unique_pdf_sha256, -> { where.not(pdf_sha256: nil).group(:pdf_sha256) }
scope :nil_pdf_sha256, -> { where(pdf_sha256: nil) }
您可以使用or
,但传递给它的关系必须在结构上兼容。因此,即使您在这两个范围中获得相同类型的关系,也不能将其与or
一起使用。
修改:为了使其在结构上相互兼容,您可以看到@AlexSantos的answer
答案 5 :(得分:0)
可以在一个查询中执行此操作,首先为每个不同的id
获取不同的pdf_sha256
作为子查询,然后在查询中通过传递子查询获取该组ID中的元素如下:
def unique_disclosures_by_pdf_sha256(company)
subquery = company.disclosures.select('MIN(id) as id').group(:pdf_sha256)
company.disclosures.where(id: subquery)
.or(company.disclosures.where(pdf_sha256: nil))
end
关于这一点的好处是ActiveRecord是延迟加载的,因此第一个subquery
将不会运行并将合并到第二个主查询以在数据库中创建单个查询。然后,它将按disclosures
以及pdf_sha256
设置为pdf_sha256
的所有nil
检索所有SELECT "disclosures".* FROM "disclosures"
WHERE (
"disclosures"."company_id" = $1 AND "disclosures"."id" IN (
SELECT MAX(id) as id FROM "disclosures" WHERE "disclosures"."company_id" = $2 GROUP BY "disclosures"."pdf_sha256"
)
OR "disclosures"."company_id" = $3 AND "disclosures"."pdf_sha256" IS NULL
)
唯一身份。
如果你好奇,给定公司,结果查询将是:
id
这个解决方案的好处是返回的值是一个ActiveRecord查询,所以在你真正需要之前它不会被加载。您还可以使用它来保持链接查询。例如,您只能选择unique_disclosures_by_pdf_sha256(company).select(:id).limit(10).each { |d| puts d }
而不是整个模型,并限制数据库返回的结果数量:
if