Laravel по-русски

Русское сообщество разработки на PHP-фреймворке Laravel.

Ты не вошёл. Вход тут.

#1 15.04.2013 16:57:11

Ikeaboy
Откуда: Киев
Сообщений: 28

Каталог с фильтрацией

Добрый день, прошу советов относительно реализации каталога товаров. Не получилось найти материалы в сети, которые бы мне помогли. Нужный мне функционал можно посмотреть тут: http://hotline()ua/computer/planshety/

Сразу приношу извинения, но кода не будет, только логика.

Функционал заведомо упрощен, без групп фильтров, категорий товаров, пагинации, и другого.

Есть список товаров (id, title, price, ...), список фильтров (id, title, suffix) и список элементов фильтров (id, filter_id, value) и связующая таблица (id, item_id, value_id).

Моя реализация работает так, при клике на элемент фильтра, который является ссылкой, генерируется запрос cо списком id всех задействованных элементов. Этот список парситься в массив, и с помощью where_in тянуться все задействованные элементы, первый запрос.

Жадно грузим все товары для этих элементов, второй запрос. После чего генерируем массив массивов из id этих товаров. Используем условие, что если элементы относятся к одному фильтру, id их товаров сливаются. На выходе массив вида: id фильтра => массив id товаров.

Получаем схождение этих массивов, и подставляем результат в where_in, получая все нужные товары, это третий запрос.

Теперь нужно сгенерировать фильтры. Грузим фильтры, жадно грузим их элементы. Четвертый и пятый запросы.

Выводим фильтра и их элементы, генерируя ссылки. Ссылки генерируються в зависимости присутствия id элемента в массиве получаемого из запроса. Если отсутствует, добавляем к этому запросу и подставляем в ссылку, если присутствует, убираем из запроса и подставляем в ссылку, присваивая ссылке класс.

Теперь о предварительном подсчете результатов. После каждого элемента в скобках присутствует число, которое показывает как измениться количество подходящих товаров после применения этого фильтра. Если из элементов этого фильтра нет ни одного активного, то просто число, которое показывает количество  товаров (17). Но если уже хоть один элемент активен, это число со знаком плюс, которое показывает сколько товаров добавиться к текущему количеству (+8). Если такое число ноль, элемент не выводиться. Сложно объяснить, лучше посмотреть образец, который я привел выше.

Начиная с этого места, я очень сомневаюсь. Жадно загрузить count с динамическим запросом не получиться.

Можно делать отдельный count запрос для каждого элемента, подставляя в условие скорректированный массив id товаров, полученный выше. Это ~много~ запросов, что меня огорчает. Можно жадно загрузить все относящиеся к элементу товары. И потом уже сравнивать массив их id с вышеупомянутым массивом. Это один запрос, но быстрее ли он первого варианта. Так же, теоретически, можно отойти от отношений и вручную использовать join, но этот вариант я пока не обдумывал.


Собственно интересует каким путем пошли бы вы? Рад буду если вы поделитесь опытом. Заранее спасибо!

Не в сети

#2 22.04.2013 08:16:21

Re: Каталог с фильтрацией

  1. Можно делать отдельный count запрос для каждого элемента, подставляя в условие скорректированный массив id товаров, полученный выше.

Это оптимальный вариант, причём можно сделать одним запросом. Есть такая штука как GROUP_CONCAT — она работает для аггрегирующих запросов (с AVG(), COUNT(), SUM() и прочими) и позволяет объединить в строку значения одного/нескольких полей как PHPjoin('-'$columns); в PHP/

Поэтому твой запрос можно сформировать так:

sqlSELECT COUNT(1), GROUP_CONCAT(DISTINCT product_id ORDER BY product_id)
  FROM products
 WHERE product_id IN (товары, по, фильтру, №1)
    OR product_id IN (товары, по, фильтру, №2)
    OR ...

Тему перенёс в «Продвинутое использование».

Не в сети

#3 22.04.2013 22:38:59

Ikeaboy
Откуда: Киев
Сообщений: 28

Re: Каталог с фильтрацией

Спасибо за ответ! Но, насколько я понял, такой подход предполагает отдельный запрос для каждого элемента фильтра. Это подход быстрее чем один запрос, а затем манипуляция с массивами, я правильно понял? Если же, вы имели в виду, вообще один запрос сразу для всех элементов, я правда, не понимаю как можно выстроить такую конструкцию в Fluent.

Не в сети

#4 22.04.2013 22:52:16

Re: Каталог с фильтрацией

  1. Если же, вы имели в виду, вообще один запрос сразу для всех элементов, я правда, не понимаю как можно выстроить такую конструкцию в Fluent.

Через PHPDB::raw() для GROUP_CONCAT. В кратце схема такая:

  1. Доходишь до этапа, когда у тебя есть списки найденных ID товаров по каждому фильтру
  2. Создаёшь WHERE product_id IN (...) — просто проходишь по фильтрам, обираешь все ID товаров в один массив, удаляешь повторения (хотя можно и не удалять, БД это сделает сама) и делаешь PHP'IN '.join(', '$ids)
  3. Выполняешь запрос с GROUP_CONCAT
  4. В результате у тебя есть набор строк: колонка с числом совпадений (COUNT(1)) и колонка с ID, объединёнными запятыми. Проходишь по всем строкам, находишь для каждой строки фильтр (сравниваешь список ID из этого запроса со списком ID от фильтра) и вот ты имеешь число товаров, которые подпали именно под этот фильтр.

Выполняется один запрос. Разбор результата должен быть довольно быстрым.

Не в сети

#5 23.04.2013 19:03:38

Ikeaboy
Откуда: Киев
Сообщений: 28

Re: Каталог с фильтрацией

Спасибо, попробую!

Не в сети

Подвал раздела