Как узнать, сколько записей одной модели связано с объектами ассоциации? - PullRequest
0 голосов
/ 28 мая 2019

У меня две модели - Property & Photos.

class Property < ActiveRecord::Base
  has_many :photos, dependent: :destroy
end

class Photo < ActiveRecord::Base
  belongs_to :property
end

Все, что я хочу сделать, - это создать область, которая возвращает только те свойства, которые действительно имеют фотографии (т.е. photos.count > 0).

Я пробовал миллион итераций запросов, и они не работают по той или иной причине.

Посмотрите некоторые примеры того, что я пробовал, и результаты:

[32] pry(main)> Property.includes(:photos).where('photos.count > 0').count
   (4.1ms)  SELECT COUNT(DISTINCT "properties"."id") FROM "properties" LEFT OUTER 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...
                                                             ^
[33] pry(main)> Property.joins(:photos).where('photos.count > 0').count
   (11.1ms)  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...
                                                             ^

[38] pry(main)> Property.joins(:photos).count("properties.id").count
   (158.2ms)  SELECT COUNT(properties.id) FROM "properties" INNER JOIN "photos" ON "photos"."property_id" = "properties"."id"
NoMethodError: undefined method `count' for 72604:Fixnum
from (pry):38:in `__pry__'

[39] pry(main)> Property.joins(:photos).count("properties.id")
   (50.6ms)  SELECT COUNT(properties.id) FROM "properties" INNER JOIN "photos" ON "photos"."property_id" = "properties"."id"
=> 72604

[40] pry(main)> Photo.joins(:properties).count("photos.id")
ActiveRecord::ConfigurationError: Association named 'properties' was not found on Photo; perhaps you misspelled it?
from /.rvm/gems/ruby-2.3.7@myapp/gems/activerecord-3.2.22.5/lib/active_record/associations/join_dependency.rb:112:in `build'

[41] pry(main)> Photo.joins(:property).count("photos.id")
   (65.0ms)  SELECT COUNT(photos.id) FROM "photos" INNER JOIN "properties" ON "properties"."id" = "photos"."property_id"
=> 72604

[42] pry(main)> Photo.joins(:property).count("photos.id")
   (60.5ms)  SELECT COUNT(photos.id) FROM "photos" INNER JOIN "properties" ON "properties"."id" = "photos"."property_id"
=> 72604

[43] pry(main)> Property.joins(:photos).count("properties.id").distinct
   (46.4ms)  SELECT COUNT(properties.id) FROM "properties" INNER JOIN "photos" ON "photos"."property_id" = "properties"."id"
NoMethodError: undefined method `distinct' for 72604:Fixnum
from (pry):43:in `__pry__'

[44] pry(main)> Property.joins(:photos).distinct.count("properties.id")
=> 0

Это должно быть просто, но по некоторым причинам это намного сложнее, чем я ожидал.

Мысли

Ответы [ 3 ]

1 голос
/ 30 мая 2019

Чтобы получить только Properties, которые на самом деле имеют photos (то есть photos.count > 0), вам нужно выполнить inner join из двух таблиц.

В рельсах 5 вы можете сделать этопо приведенной ниже команде

Property.joins(:photos)

Это будет преобразовано в SQL как

SELECT  "properties".* FROM "properties" INNER JOIN "photos" ON "photos"."property_id" = "properties"."id"

Если вы хотите добавить больше условий в свои запросы, вы можете добавить Where предложение

Property.joins(:photos).where(properties: {id: [1, 2]})
0 голосов
/ 30 мая 2019

Использование Property.joins(:photos) (которое выполняет внутреннее соединение) вернет свойства, имеющие связанные фотографии.Имеются в виду фотографии, которые имеют property_id.Хотя ответ с использованием left_outer_joins, LEFT JOIN или LEFT OUTER JOIN будет работать, он неправильно использует левое соединение, имея .where(photos: { id: nil }).INNER JOIN, JOIN или joins между Property и Photo приведут к тому, что я сказал в начале этого ответа.Левые объединения вернут все свойства с или без связанных фотографий.

enter image description here

0 голосов
/ 28 мая 2019

В Rails-5 , вы можете использовать left_outer_joins ,

Property.left_outer_joins(:photos).where(photos: {id: nil})

Сгенерированный SQL будет,

SELECT properties.*
FROM properties 
LEFT OUTER JOIN photos 
ON photos.property_id = property.id
WHERE photos.id IS NULL

In Rails-3 , Вы можете попробовать следующее

Property.joins("LEFT OUTER JOIN photos ON properties.id = photos.property_id").where(photos: {id: nil})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...