Pregunta Los rieles encuentran un registro con cero has_many records asociados


Esto parece bastante simple, pero no puedo hacer que aparezca en Google.

Si tengo:

class City < ActiveRecord::Base
  has_many :photos
end

class Photo < ActiveRecord::Base
  belongs_to :city
end

Quiero encontrar todas las ciudades que no tienen fotos. Me encantaría poder llamar algo así como ...

City.where( photos.empty? )

... pero eso no existe. Entonces, ¿cómo haces este tipo de consulta?


Actualizar: Al haber encontrado una respuesta a la pregunta original, tengo curiosidad, ¿cómo construyes la inversa?

IE: si quisiera crear estos como ámbitos:

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

74
2018-03-08 06:25


origen


Respuestas:


Bah, lo encontró aquí: https://stackoverflow.com/a/5570221/417872

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

107
2018-03-08 06:31



En Carriles 5, para encontrar todas las ciudades que no tienen fotos, puedes usar left_outer_joins:

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

que dará como resultado SQL como:

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

Utilizando includes:

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

tendrá el mismo resultado, pero dará lugar a SQL mucho más feo como:

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

27
2017-09-09 11:11



Al tratar de encontrar registros sin registros coincidentes de la tabla unida, debe usar una UNIÓN EXTERIOR IZQUIERDA

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')

22
2018-05-20 09:42



Usé un join para obtener todos los con fotos:

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

Más fácil de escribir y entender, para ese caso particular. No estoy seguro de cuál es la eficiencia de hacer una unión vs hacer una incluye, sin embargo


4
2018-04-29 22:38