За последние 24 часа нас посетили 22395 программистов и 1150 роботов. Сейчас ищут 702 программиста ...

Типа умный фильтр товаров в один запрос к бд

Тема в разделе "PHP для новичков", создана пользователем Bordon, 5 ноя 2020.

Метки:
  1. Bordon

    Bordon Новичок

    С нами с:
    9 окт 2020
    Сообщения:
    3
    Симпатии:
    0
    Всем привет. В общем я создал фильтр товаров и решил что было бы не плохо чтоб обсчитывалось кол-во товаров для каждой опции , а также пересчитывалось при выборе фильтра'ов чтоб при отсутствие результатов просто disable'ить checkbox.

    Вообще я кожу на symfony по этому код будет представлен в doctrine которая не поддерживает без костылей подзапросов , но и на sql я тоже предоставлю варинаты.

    Моя проблема - как мне соединить все COUNT в один запрос, чтоб бд не офигевала.
    Вообще говорят что такое лучше решать через elasticsearch если есть мнение насчёт этого не стесняйтесь высказывать его.
    И так поехали. Модель product'a - EAV
    БД:
    db12.png

    Опции фильтров выглядят так:
    PHP:
    1.         $options = array(
    2.             "brand" => array("Brand", "Another Brand", "Some Brand"),
    3.             "country" => array("Poland", "Russia", "Ukraine")
    4.         );
    5. //        но для примера будет достаточно этого
    6.         $options = ['Poland', 'Russia', 'Ukraine'];
    вот как я подсчитываю кол-во:
    PHP:
    1.     public function findAllCountedOptions()
    2.     {
    3.         $arr = ['Poland', 'Russia', 'Ukraine'];
    4.  
    5.         $result = [];
    6.  
    7.         foreach ($arr as $item){
    8.             $qb = $this->getEntityManager()->createQueryBuilder();
    9.             $query = $qb
    10.                 ->addSelect($qb->expr()->countDistinct('p.id'))
    11.                 ->from(Product::class, 'p')
    12.                 ->innerJoin('p.attributeValues', 'av_s')
    13.                 ->andWhere('av_s.value = :value_s')
    14.                 ->setParameter('value_s', $item)
    15.  
    16. //              при условие что выбран фильтр Plastic
    17. //            ->innerJoin('p.attributeValues', 'av_p')
    18. //            ->andWhere('av_p.value = :value_p')
    19. //            ->setParameter('value_p', 'Plastic')
    20.  
    21.                 ->getQuery()
    22.                 ->getResult()
    23.             ;
    24.             $result[$item] = $query[0][1];
    25.  
    26.         }
    27.        
    28.         return $result;
    29.     }
    на выходе получаем такой массив:
    PHP:
    1. array(  "Poland" => "58"
    2.   "Russia" => "65"
    3.   "Ukraine" => "58" );

    вот так выглядит этот запрос в sql:
    PHP:
    1. SELECT COUNT(DISTINCT p0_.id) AS sclr_0
    2. FROM product p0_
    3. INNER JOIN attribute_value a1_ ON p0_.id = a1_.product_id
    4. WHERE a1_.value = ?
    Вообще можно напрямую к таблице value обращаться sql:
    PHP:
    1. SELECT COUNT(DISTINCT av.product_id)
    2. FROM attribute_value AS av WHERE av.value = 'Plastic'
    но я не знаю как тут добавлять условие , когда несколько фильтров уже выбрано , то есть с таблицей product я просто через innerjoin добавляю select и новый параметр , как join'ить одну таблицу я не знаю.

    Короче возможно ли вообще COUNT p.id для нескольких опциий в один запрос, ну чтоб кол-во был для каждой опции было отдельно посчитано.
    Спасибо за ваше время.