Rails encuentra un padre que tiene dos hijos con cierto atributo

Tengo más de 100,000 objetos en mi base de datos para diferentes Productos. Cada producto tiene 4-6 variantes. Debido a esto, no es fácil editar perezosamente una gran cantidad de datos al iterar todo. Debido a esto, estoy tratando de obtener solo la cantidad exacta de Productos que necesito.

Hasta ahora, puedo obtener todos los productos que tienen una variante con el atributo de tamaño ‘SM’.

El problema es obtener todos los productos que tienen una variante con tamaño ‘MD’ y ‘SM’.

Este es el código que estoy usando Product.joins(:variants).where('variants.size = ?', 'SM')

He intentado agregar .where('variants.size = ?', 'MD') a él, pero eso funciona.

Qué tal esto

 Product.where( id: Variant.select(:product_id) .where(size: 'SM') ).where(id: Variant.select(:product_id) .where(size: 'MD') ) 

Esto debería generar algo parecido a

 SELECT products.* FROM products WHERE products.id IN (SELECT variants.product_id FROM variants WHERE size = 'SM') AND products.id IN (SELECT variants.product_id FROM variants WHERE size = 'MD') 

por lo que la identificación del producto debe estar en ambas listas para ser seleccionado.

Además Esto también debería funcionar (no es 100% seguro)

 Product.where(id: Product.joins(:variants) .where(variants: {size: ['SM', 'MD']}) .group(:id) .having('COUNT(*) = 2').select(:id) 

Que debería generar algo como

 SELECT products.* FROM products WHERE products.id IN ( SELECT products.id FROM products INNER JOIN variants ON variants.product_id = products.id WHERE variants.size IN ('SM','MD') GROUP BY products.id HAVING Count(*) = 2 

Una opción más

 p_table = Products.arel_table v_table = Variant.arel_table sm_table = p_table.join(v_table) .on(v_table[:product_id].eq(p_table.[:id]) .and(v_table[:size].eq('SM')) ) md_table = p_table.join(v_table) .on(v_table[:product_id].eq(p_table.[:id]) .and(v_table[:size].eq('MD')) ) Product.joins(sm_table.join_sources).joins(md_table.join_sources) 

SQL

 SELECT products.* FROM products INNER JOIN variants on variants.product_id = products.id AND variants.size = 'SM' INNER JOIN variants on variants.product_id = products.id AND variants.size = 'MD' 

Estas 2 uniones deben hacer cumplir las pequeñas y medianas debido a la UNIÓN INTERNA

En mi humilde opinión necesitas usar un poco más de SQL en lugar de Rails magic para crear consultas de bases de datos como esa.

 Product .joins('INNER JOIN variants as sm_vs ON sm_vs.product_id = products.id') .joins('INNER JOIN variants as md_vs ON md_vs.product_id = products.id') .where(sm_vs: { size: 'SM' }) .where(md_vs: { size: 'MD' }) 

O simplificado, como @engineersmnky sugirió:

 Product .joins("INNER JOIN variants as sm_vs ON sm_vs.product_id = products.id AND sm_vs.size = 'SM'") .joins("INNER JOIN variants as md_vs ON md_vs.product_id = products.id AND sm_vs.size = 'MD'") 

Ambas consultas hacen básicamente lo mismo. Simplemente elige la versión que más te guste.

Product.joins (: variantes) .where (‘variantes.size =? OR variantes.size =?’, ‘SM’, ‘MD’)