如何在 join table 而不是 OR / IN 查询中查找具有所有必需 has_many 关联的记录
How to find a record having all required has_many associations in join table instead of OR / IN query
我有一家餐厅 Table、一家美食 Table 和一个连接多对多的连接 table。我想找到一家与两种特定美食相匹配的餐厅,即找到连接 table 中列出的与美食 1 和美食 2 相关的餐厅。
我可以用 each 和 includes 一起破解一些东西,但感觉在使用 ActiveRecord 构建查询时一定缺少一些直接和明显的东西。
Restaurant
ID| Name
1 | McDonalds
2 | Taco Bell
Cuisine
ID| Style
1 | American
2 | Mexican
3 | Fast Food
Restaurant_Cuisines
ID | Restaurant_ID | Cuisine_ID
1 | 1 | 1
2 | 1 | 3
3 | 2 | 2
4 | 2 | 3
我希望能够查询既提供美式食品又提供快餐的餐厅,这样可以返回麦当劳而不是塔可钟,因为塔可钟提供快餐而不是美式。
假设您有外键的 ID,您可以使用 joins
并像这样传递连接 table 的 ID:
cuisine_ids = Cuisine.where(Style: ['American', 'Mexican']).pluck(:id)
restaurants = Restaurant.joins(:cuisines).where(cuisines: {id: cuisine_ids})
我可以想到以下查询,它可能不是最优化的解决方案,但它给出了正确的答案,并且可以指导获得优化答案的方向。
rest_ids = Restaurant_Cuisines.where(Cuisine_ID: 1).pluck(:Restaurant_ID) && Restaurant_Cuisines.where(Cuisine_ID: 3).pluck(:Restaurant_ID)
Restaurant.where(id: rest_ids)
如果需要泛化:
def specific_restaurant(cuisine_ids)
ids = cuisine_ids.map { |id| Restaurant_ID.where(Cuisine_ID: id).pluck(:Restaurant_ID) }.reduce(:&)
Restaurant.where(id: ids) if ids.present?
end
肯定是 N+1
,其中 N
是 cuisine_ids
,但如果 N
是 limited/few 也没有坏处。
更新 - 最后,单个查询!
def specific_restaurant(cuisine_ids)
ids = RestaurantCuisine.where(cuisine_id: cuisine_ids).group(:restaurant_id).having("count(*) = #{cuisine_ids.count}").pluck(:restaurant_id)
Restaurant.where(id: ids) if ids.present?
end
我有一家餐厅 Table、一家美食 Table 和一个连接多对多的连接 table。我想找到一家与两种特定美食相匹配的餐厅,即找到连接 table 中列出的与美食 1 和美食 2 相关的餐厅。
我可以用 each 和 includes 一起破解一些东西,但感觉在使用 ActiveRecord 构建查询时一定缺少一些直接和明显的东西。
Restaurant
ID| Name
1 | McDonalds
2 | Taco Bell
Cuisine
ID| Style
1 | American
2 | Mexican
3 | Fast Food
Restaurant_Cuisines
ID | Restaurant_ID | Cuisine_ID
1 | 1 | 1
2 | 1 | 3
3 | 2 | 2
4 | 2 | 3
我希望能够查询既提供美式食品又提供快餐的餐厅,这样可以返回麦当劳而不是塔可钟,因为塔可钟提供快餐而不是美式。
假设您有外键的 ID,您可以使用 joins
并像这样传递连接 table 的 ID:
cuisine_ids = Cuisine.where(Style: ['American', 'Mexican']).pluck(:id)
restaurants = Restaurant.joins(:cuisines).where(cuisines: {id: cuisine_ids})
我可以想到以下查询,它可能不是最优化的解决方案,但它给出了正确的答案,并且可以指导获得优化答案的方向。
rest_ids = Restaurant_Cuisines.where(Cuisine_ID: 1).pluck(:Restaurant_ID) && Restaurant_Cuisines.where(Cuisine_ID: 3).pluck(:Restaurant_ID)
Restaurant.where(id: rest_ids)
如果需要泛化:
def specific_restaurant(cuisine_ids)
ids = cuisine_ids.map { |id| Restaurant_ID.where(Cuisine_ID: id).pluck(:Restaurant_ID) }.reduce(:&)
Restaurant.where(id: ids) if ids.present?
end
肯定是 N+1
,其中 N
是 cuisine_ids
,但如果 N
是 limited/few 也没有坏处。
更新 - 最后,单个查询!
def specific_restaurant(cuisine_ids)
ids = RestaurantCuisine.where(cuisine_id: cuisine_ids).group(:restaurant_id).having("count(*) = #{cuisine_ids.count}").pluck(:restaurant_id)
Restaurant.where(id: ids) if ids.present?
end