如何计算具有一个或多个关联对象的记录数?

时间:2019-01-17 07:37:12

标签: ruby-on-rails join ruby-on-rails-3.2 associations

我有一个Property的{​​{1}}模型。我想计算有一张或多张照片的has_many :photos的数量。

我该怎么做?

我尝试过简单的方法:

properties

收件人:

> Property.where('properties.photos.count > ?', 0).count

   (3.1ms)  SELECT COUNT(*) FROM "properties" WHERE (properties.photos.count > 1)
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  missing FROM-clause entry for table "photos"
LINE 1: SELECT COUNT(*) FROM "properties"  WHERE (properties.photos....
                                                  ^
: SELECT COUNT(*) FROM "properties"  WHERE (properties.photos.count > 0)
from /ruby-2.3.0@myproject/gems/activerecord-3.2.22.5/lib/active_record/connection_adapters/postgresql_adapter.rb:1163:in `async_exec'
Caused by PG::UndefinedTable: ERROR:  missing FROM-clause entry for table "photos"
LINE 1: SELECT COUNT(*) FROM "properties"  WHERE (properties.photos....

到更高级:

> Property.joins(:photos).where('photos.count > ?', 0).count

   (3.7ms)  SELECT COUNT(*) FROM "properties" INNER JOIN "photos" ON "photos"."property_id" = "properties"."id" WHERE (photos.count > 0)
ActiveRecord::StatementInvalid: PG::GroupingError: ERROR:  aggregate functions are not allowed in WHERE
LINE 1: ..."photos"."property_id" = "properties"."id" WHERE (photos.cou...
                                                             ^
: SELECT COUNT(*) FROM "properties" INNER JOIN "photos" ON "photos"."property_id" = "properties"."id" WHERE (photos.count > 0)
from ruby-2.3.0@myproject/gems/activerecord-3.2.22.5/lib/active_record/connection_adapters/postgresql_adapter.rb:1163:in `async_exec'
Caused by PG::GroupingError: ERROR:  aggregate functions are not allowed in WHERE
LINE 1: ..."photos"."property_id" = "properties"."id" WHERE (photos.cou...

和其他一些变体,它们都产生相似的错误。

我在做什么错了?

注意:我只想拥有>Property.includes(:photos).group(['property.id', 'photos.id']).order('COUNT(photos.id) DESC').count (0.6ms) SELECT COUNT(DISTINCT "properties"."id") AS count_id, property.id AS property_id, photos.id AS photos_id FROM "properties" LEFT OUTER JOIN "photos" ON "photos"."property_id" = "properties"."id" GROUP BY property.id, photos.id ORDER BY COUNT(photos.id) DESC ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "property" LINE 1: ...CT COUNT(DISTINCT "properties"."id") AS count_id, property.i... ^ : SELECT COUNT(DISTINCT "properties"."id") AS count_id, property.id AS property_id, photos.id AS photos_id FROM "properties" LEFT OUTER JOIN "photos" ON "photos"."property_id" = "properties"."id" GROUP BY property.id, photos.id ORDER BY COUNT(photos.id) DESC from ruby-2.3.0@myproject/gems/activerecord-3.2.22.5/lib/active_record/connection_adapters/postgresql_adapter.rb:1163:in `async_exec' Caused by PG::UndefinedTable: ERROR: missing FROM-clause entry for table "property" LINE 1: ...CT COUNT(DISTINCT "properties"."id") AS count_id, property.i... 的{​​{1}}的数量。我不需要所有属性和照片数量的哈希。换句话说,如果我的数据库中有5000个属性,我想构建一个范围,使其仅返回实际包含照片的属性。

6 个答案:

答案 0 :(得分:2)

编辑:

Property.joins(:photos).group('photos.property_id').having('count(photos.property_id) > 1').count

#=> {1234=>2}  # 1234 is property id 2 is count of photos 

您将获得property_ids及其相关照片的数量。

旧答案:

您可以获得至少一张与之相关的照片

Property.includes(:photos).where.not(photos: { property_id: nil })

由于您正在使用Rails 3.2 .not,因此您必须使用

Property.includes(:photos).where("property_id IS NOT null")

答案 1 :(得分:1)

由于您只需要PhotoProperty.joins(:photos) s,那么您就需要一个INNER JOIN。

class Property < ActiveRecord::Base
  scope :with_photos, -> {joins(:photos)} 
end 

就是这样。如果您想要一个范围,则

Property.with_photos.count(distinct: true)  

使用rails 3.2获取计数

Property.count(joins: :photos, distinct: true) 

您还可以在rails 3.2中使用:

SELECT 
  COUNT(DISTINCT properties.id) 
FROM 
  properties
  INNER JOIN photos ON photos.property_id = properties.id

ActiveRecord::Calculations#count Doc

这将执行

{{1}}

答案 2 :(得分:1)

您可以尝试这样,我已经在我的项目中完成了

Photo.group(:property_id).count

您将获得具有照片数量

属性ID
results = { 3314=>3, 2033=>3, 3532=>2, 3565=>6, 3510=>1, 3022=>7, 648=>2, 570=>3, 4678=>3, 3540=>1, 3489=>4, 536=>1, 1715=>4 }

答案 3 :(得分:0)

尝试一下:

SRV_ST_STOPPED

Source

更高效(4个以上的滑轨):

class Property < ApplicationRecord
  has_many :photos

  def self.with_photos
    self.all.reject { |p| p.photos.empty? }
  end
end

Property.with_photos.count

Source

更高效(5.1级以上的滑轨):

Property.joins(:photos).uniq.count

Source

答案 4 :(得分:0)

根据您的要求,您可以尝试

  

1)简单计数具有1个或多个属性的数量   照片

要获取拥有一张或多张照片的属性的数量,可以执行此操作

Property.joins(:photos).distinct.count

由于我们没有使用group,因此distinctuniq是必需的。 distinct将返回ActiveRecord_Relation,而uniq将返回Array

  

2)我希望返回该组属性,以便我可以   创建这些属性的范围。另外,我确实有很多   超过1张照片的房地产。

要获取具有一张或多张照片的所有属性对象,可以使用相同的查询:

Property.joins(:photos).distinct

或者您可以使用group_by子句:

Property.joins(:photos).group('properties.id')

区别在于,当您在size查询中使用group方法时,它将返回一个哈希,其哈希值以property_id为键,而该属性上的照片数量为值。

性能更新:

如果您始终需要关联对象的数量,并且想要有效地获取它,则可以像这样使用counter_cache

class Photo < ApplicationRecord
  belongs_to :property, counter_cache: true
end

class Property < ApplicationRecord
  has_many :photos
end

然后,您将不得不在属性表中添加一个名为photos_count的列,并且每次添加新的照片记录或删除现有的照片记录时,Rails都会自动更新该列。然后,您也可以直接查询:

Property.where('photos_count > ?', 1)

这是可选的,如果数据获取遇到性能问题,则可以执行此操作。

答案 5 :(得分:0)

Property.includes(:photos).where("SELECT count(photos.id) > 0 FROM photos WHERE property_id = properties.id")

作为作用域:

scope :with_photos, -> { where("SELECT count(photos.id) > 0 FROM photos WHERE property_id = properties.id") }