我有一张餐厅桌,一张美食桌和一张连接多人节目的连接桌。我想找一家与两种特色美食相匹配的餐厅,即找到连接餐桌上列出的连接到Cuisine 1和Cuisine 2的餐厅。
我可以和每个东西一起破解和包含,但感觉在使用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
我希望能够查询同时服务于美国和快餐的餐厅,这会让我回到麦当劳而不是Taco Bell,因为Taco Bell供应快餐而不是美国。
我可以想到以下查询可能不是最优化的解决方案,但它给出了正确的答案,并可以指导方向以获得优化的答案。
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
有限/很少没有伤害。
更新 - 最后,单个查询!
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
假设您拥有外键的ID,您可以使用joins
并传递连接表的ID,如下所示:
cuisine_ids = Cuisine.where(Style: ['American', 'Mexican']).pluck(:id)
restaurants = Restaurant.joins(:cuisines).where(cuisines: {id: cuisine_ids})