Как найти запись, имеющую все необходимые ассоциации has_many в таблице соединений вместо запроса OR / IN - PullRequest
0 голосов
/ 18 апреля 2019

У меня есть столик в ресторане, столик для кухни и стол для соединения, соединяющий «многие ко многим».Я хочу найти Ресторан, который соответствует двум конкретным кухням, т. Е. Найти Ресторан, который указан в объединенной таблице и связан с Кухнями 1 и Кухни 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 предлагает фаст-фуд, но не американский.

Ответы [ 2 ]

2 голосов
/ 18 апреля 2019

Я могу подумать о следующем запросе, который может быть не самым оптимальным решением, но он дает правильный ответ и может помочь в поиске оптимизированного ответа.

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
0 голосов
/ 18 апреля 2019

Если у вас есть идентификаторы внешних ключей, вы можете использовать joins и передать идентификаторы таблицы соединения следующим образом:

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

restaurants = Restaurant.joins(:cuisines).where(cuisines: {id: cuisine_ids})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...