2013-05-09 2 views
0

Ресторан has_many БлюдоКомплексные Rails/Postgres SQL оптимизации

Dish 
has_many Photo 

Photo 
belongs_to Dish 

Restaurant 1 
    Dish 1 
    Photo 1 May 9, 1:00 PM 
    Dish 2 
    Photo 2 May 9, 2:00 PM 
    Dish 3 
    Photo 3 May 9, 3:00 PM 

Restaurant 2 
    Dish 4 
    Photo 4 May 9, 1:00 PM 
    Dish 5 
    Photo 5 May 9, 2:00 PM 
    Dish 6 
    Photo 6 May 9, 3:00 PM 

Я пытаюсь получить последние 50 фотографий с лимитом 2 посудомоечных фотографий в ресторане. Учитывая приведенные выше данные, я смогу получить фотографии с идентификаторами 2, 3, 5, and 6

Мое текущее исполнение является уродливым, если не сказать больше.

hash = {} 
bucket = [] 
Photo.includes(:dish => [:restaurant]).order("created_at desc").each do |p| 
    restaurant_id = p.dish.restaurant.id 
    restaurant_count = hash[restaurant_id].present? ? hash[restaurant_id] : 0 
    if restaurant_count < 2 
    bucket << p 
    hash[restaurant_id] = restaurant_count + 1 
    end 
    # if you've got 50 items short circuit. 
end 

Я не могу не чувствовать, что существует гораздо более эффективное решение. Любые идеи были бы хорошы :-).

+1

Это не тривиальная логика для реализации даже в чистом SQL. Возможно, вам лучше поддерживать специализированную структуру очередей, которая всегда поддерживает список из этих 50 фотографий. Затем вы можете сделать ограничение 2-на-ресторан, когда вы введете новую фотографию. Очевидно, это было бы оптимизировано для нескольких-write-many-reads. – mikeryz

+0

Да, это был мой следующий шаг, так как я действительно совершенно не знаю, когда дело доходит до подзапросов. – lemon

+0

Если вы хотите, чтобы какой-либо Google Googling настроил SQL, примерно так: http://books.google.com/books?id=thTju-4duY4C&lpg=PP1&ots=nFmsRSwKu0&dq=enterprise%20rails&pg=PA147#v=onepage&q&f = false, вероятно, будет лучшим способом сделать это ... – mikeryz

ответ

1

Там должен быть способ «группировки» запрос, но, по крайней мере, следующие несколько проще:

def get_photo_bucket 
    photo_bucket = restaurant_control = [] 
    Photos.includes(:dish => [:restaurant]).order("created_at desc").each do |photo| 
    if photo_bucket.count < 50 && restaurant_control.count(photo.dish.restaurant.id) < 2 
     photo_bucket << photo 
     restaurant_control << photo.dish.restaurant.id 
    end 
    end 
    photo_bucket 
end 
+0

К сожалению, это просто вернет последние два блюда из каждого ресторана, а не 50 самых последних с лимитом в два на человека. – mikeryz

+0

Извините @mikeryz, я неправильно понял ваши ограничения. Я отредактировал ответ. – Galen