Rails查找与零has_manylogging关联的logging

这似乎相当简单,但我不能让它在Google上出现。

如果我有:

class City < ActiveRecord::Base has_many :photos end class Photo < ActiveRecord::Base belongs_to :city end 

我想find所有没有照片的城市。 我很乐意能够打电话给…

 City.where( photos.empty? ) 

…但不存在 那么,你如何做这种查询?


更新:现在已经find了原始问题的答案,我很好奇,你如何构造反向?

IE:如果我想创build这些作为示波器:

 scope :without_photos, includes(:photos).where( :photos => {:city_id=>nil} ) scope :with_photos, ??? 

嗯,在这里find它: https : //stackoverflow.com/a/5570221/417872

 City.includes(:photos).where(photos: { city_id: nil }) 

当试图从连接表中查找没有匹配logging的logging时,您需要使用LEFT OUTER JOIN

 scope :with_photos, joins('LEFT OUTER JOIN photos ON cities.id = photos.city_id').group('cities.id').having('count(photos.id) > 0') scope :without_photos, joins('LEFT OUTER JOIN photos ON cities.id = photos.city_id').group('cities.id').having('count(photos.id) = 0') 

Rails 5中 ,要查找所有没有照片的城市,可以使用left_outer_joins

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

这将导致SQL如下所示:

 SELECT cities.* FROM cities LEFT OUTER JOIN photos ON photos.city_id = city.id WHERE photos.id IS NULL 

使用includes

 City.includes(:photos).where(photos: {id: nil}) 

将会有相同的结果,但会导致很多丑陋的SQL,如:

 SELECT cities.id AS t0_r0, cities.attr1 AS t0_r1, cities.attr2 AS t0_r2, cities.created_at AS t0_r3, cities.updated_at AS t0_r4, photos.id AS t1_r0, photos.city_id AS t1_r1, photos.attr1 AS t1_r2, photos.attr2 AS t1_r3, photos.created_at AS t1_r4, photos.updated_at AS t1_r5 FROM cities LEFT OUTER JOIN photos ON photos.city_id = cities.id WHERE photos.id IS NULL 

我用一个join来获得所有的照片:

scope :with_photos, -> { joins(:photos).distinct }

更容易写和理解,特殊情况下。 不过,我不确定做一个连接和一个包含的效率是多less