iro*_*and 5 postgresql activerecord ruby-on-rails
我有一个Company模型有很多Disclosures. 将Disclosure有一个名为列title,pdf和pdf_sha256。
class Company < ActiveRecord::Base
has_many :disclosures
end
class Disclosure < ActiveRecord::Base
belongs_to :company
end
Run Code Online (Sandbox Code Playgroud)
我想让它独特的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
Run Code Online (Sandbox Code Playgroud)
如何使用 ActiveRecord 查询获得相同的结果?
可以在一个查询中完成此操作,首先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
Run Code Online (Sandbox Code Playgroud)
这样做的好处是 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
)
Run Code Online (Sandbox Code Playgroud)
该解决方案的优点在于,返回的值是一个 ActiveRecord 查询,因此只有在您真正需要时才会加载它。您还可以使用它来保持链接查询。例如,您可以仅选择而id不是整个模型并限制数据库返回的结果数量:
unique_disclosures_by_pdf_sha256(company).select(:id).limit(10).each { |d| puts d }
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3237 次 |
| 最近记录: |