如何在连接表中找到具有所有必需的has_many关联的记录,而不是OR / IN查询

问题描述 投票:0回答:2

我有一张餐厅桌,一张美食桌和一张连接多人节目的连接桌。我想找一家与两种特色美食相匹配的餐厅,即找到连接餐桌上列出的连接到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供应快餐而不是美国。

ruby activerecord sinatra
2个回答
2
投票

我可以想到以下查询可能不是最优化的解决方案,但它给出了正确的答案,并可以指导方向以获得优化的答案。

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,其中Ncuisine_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

0
投票

假设您拥有外键的ID,您可以使用joins并传递连接表的ID,如下所示:

cuisine_ids = Cuisine.where(Style: ['American', 'Mexican']).pluck(:id)

restaurants = Restaurant.joins(:cuisines).where(cuisines: {id: cuisine_ids})
© www.soinside.com 2019 - 2024. All rights reserved.