Question

I want to filter a product collection with pairs of attributes match. For example get product collection which has (brand="Toyota" AND color="Red") OR (brand="Ford" AND color="Blue") OR (brand="BMW" AND color="White").

How can I do that with addAttributeToFilter or AddFieldToFilter?

Was it helpful?

Solution 3

Look like addAttributeToFilter or addFieldToFilter will always insert the where clause as AND condition. I ended up building sql on my own:

use Magento\Catalog\Api\Data\ProductAttributeInterface;
use Magento\Catalog\Model\Product;
use Magento\Catalog\Model\ProductRepository;
use Magento\Eav\Model\Attribute;
use Magento\Eav\Model\AttributeRepository;
use Magento\Framework\Api\FilterBuilder;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\App\ResourceConnection;

class Helper {
    public function __construct(
        ProductRepository $productRepository,
        AttributeRepository $attributeRepository,
        SearchCriteriaBuilder $searchCriteriaBuilder,
        FilterBuilder $filterBuilder,
        ResourceConnection $resourceConnection
    ) {
        $this->productRepository = $productRepository;
        $this->attributeRepository = $attributeRepository;
        $this->searchCriteriaBuilder = $searchCriteriaBuilder;
        $this->filterBuilder = $filterBuilder;
        $this->resourceConnection = $resourceConnection;
    }

    /**
     * Get product array from set of multiple attribute values
     * Param structure:
     *      $attributes: array(
     *          $attributeCode1,
     *          $attributeCode2,
     *          ...
     *      )
     *      $valueSets: array(
     *          array(
     *              $attributeCode1 => $value1,
     *              $attributeCode2 => $value2,
     *              ...
     *          ),
     *          array(
     *              $attributeCode1 => $value3,
     *              $attributeCode2 => $value4,
     *              ...
     *          ),
     *      )
     *
     * @param array $attributes
     * @param array $valueSets
     *
     * @return Product[]
     */
    public function getProductsFromAttributeValues($attributes, $valueSets)
    {
        $attributeSearchResult = $this->attributeRepository->getList(
            ProductAttributeInterface::ENTITY_TYPE_CODE,
            $this->searchCriteriaBuilder->addFilters(
                [
                    $this->filterBuilder
                        ->setField('attribute_code')
                        ->setConditionType('in')
                        ->setValue($attributes)
                        ->create(),
                ]
            )->create()
        );


        $connection = $this->resourceConnection->getConnection();
        $select = $connection->select()
                             ->from(['e' => $connection->getTableName('catalog_product_entity')], 'entity_id');

        /** @var Attribute $item */
        foreach ($attributeSearchResult->getItems() as $item) {
            $attributeCode = $item->getAttributeCode();
            $attributeId = $item->getAttributeId();
            $select->joinInner(
                ["at_$attributeCode" => $connection->getTableName('catalog_product_entity_varchar')],
                "`at_$attributeCode`.`entity_id` = `e`.`entity_id` AND `at_$attributeCode`.`attribute_id` = '$attributeId'",
                null
            );
        }

        foreach ($valueSets as $valueSet) {
            $index = 0;
            foreach ($valueSet as $attributeCode => $value) {
                if ($index === 0) {
                    $select->orWhere("`at_$attributeCode`.`value` = ?", $value);
                } else {
                    $select->where("`at_$attributeCode`.`value` = ?", $value);
                }
                $index++;
            }
        }
        $products = [];
        foreach ($connection->fetchAll($select) as $data) {
            $products[] = $this->productRepository->getById($data['entity_id']);
        }

        return $products;
    }
}

Usage:

$helper->getProductsFromAttributeValues(
    ['brand', 'color'],
    [
        ['brand' => 'Toyota', 'color' => 'Red'],
        ['brand' => 'Ford', 'color' => 'Blue'],
        ['brand' => 'BMW', 'color' => 'White'],
    ]
)

OTHER TIPS

Try this,

example :

$collection->addAttributeToFilter([['attribute'=>'brand','like'=>'%Toyota%'],['color'=>'status', 'eq'=>'Red']]);

Another thing to look at to achieve 'OR' is:

->addFieldToFilter(
     'brand',
     ['in' => ['simple', 'configurable']]
)

Please study it deeply from this link.
https://meetanshi.com/blog/apply-or-conditions-to-collection-in-magento-2/

I hope the above link will definitely help you in this issue.
Adding another link that is similar and can help you in this topic.
https://stackoverflow.com/questions/3826474/magento-addfieldtofilter-two-fields-match-as-or-not-and
Vibhore

Try this

$collection->addAttributeToSelect('*');
$collection->addAttributeToFilter([['attribute'=>'brand','eq'=>'Toyota'],['attribute'=>'color', 'eq'=>'Red']]);

$collection->addAttributeToFilter([['attribute'=>'brand','eq'=>'Ford'],['attribute'=>'color', 'eq'=>'Blue']]);

$collection->addAttributeToFilter([['attribute'=>'brand','eq'=>'BMW'],['attribute'=>'color', 'eq'=>'White']]);

Please print this collection also to string. Use this command for printing collections
echo $collection->getSelect()->__toString();

Edit: Adding another solution

$collection->getSelect()->where(
    "(brand='Toyota' AND color='Red') OR (brand='Ford' AND color='Blue') OR (brand='BMW' AND color='White')"
);

You can do more research here .. a person asked very similar question as you asked please have a look

https://magento.stackexchange.com/questions/139488/filter-category-collection-with-nested-or-and-statements

Thanks
Vibhore

Try this :

$collection->getSelect()->where(
    "(brand='Toyota' AND color='Red') OR (brand='Ford' AND color='Blue') OR (brand='BMW' AND color='White')"
);

In this sample function we are running sql queries directly those having joins please have a look, it may be helpful, this function is written in our block.

    public function getCatData()
     {
     $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
     $resource = $objectManager->get('Magento\Framework\App\ResourceConnection');
     $connection = $resource->getConnection();
     $category_id = $this->getRequest()->getParams();
     $category_id = $category_id['id'];
         $parent="l1_";
         $parentAttr="l2_";


         $l1Query="SELECT VALUE AS NAME FROM rpt_catalog_category_entity_varchar  WHERE attribute_id=45 AND entity_id=".$category_id;

         $l2Query="SELECT DISTINCT c.entity_id AS l2_entity_id,e.value AS l2_name,g.value AS l2_url FROM rpt_catalog_category_entity AS a INNER JOIN rpt_catalog_category_entity AS c ON a.entity_id=c.parent_id INNER JOIN rpt_catalog_category_entity_int AS d ON c.entity_id=d.entity_id LEFT JOIN rpt_catalog_category_entity_varchar AS e ON d.entity_id=e.entity_id AND e.attribute_id=45 INNER JOIN rpt_catalog_category_entity_varchar AS f ON d.entity_id=f.entity_id AND f.attribute_id=48 INNER JOIN rpt_catalog_category_entity_varchar AS g ON d.entity_id=g.entity_id AND g.attribute_id=119 WHERE a.entity_id=".$category_id." AND d.attribute_id=46 AND d.value=1 ORDER BY e.value";

         $l3Query="SELECT DISTINCT c.entity_id AS l2_entity_id,g.value AS l3_name,i.value AS l3_url FROM rpt_catalog_category_entity AS a INNER JOIN rpt_catalog_category_entity AS c ON a.entity_id=c.parent_id INNER JOIN rpt_catalog_category_entity_int AS d ON c.entity_id=d.entity_id INNER JOIN rpt_catalog_category_entity AS e ON c.entity_id=e.parent_id INNER JOIN rpt_catalog_category_entity_int AS f ON e.entity_id=f.entity_id INNER JOIN rpt_catalog_category_entity_varchar AS g ON f.entity_id=g.entity_id AND g.attribute_id=45 INNER JOIN rpt_catalog_category_entity_varchar AS i ON f.entity_id=i.entity_id AND i.attribute_id=119 WHERE a.entity_id=".$category_id." AND d.attribute_id=46 AND d.value=1 AND f.attribute_id=46 AND f.value=1 ORDER BY g.value";
         $l4Query="SELECT value AS description FROM rpt_catalog_category_entity_text WHERE attribute_id=47 AND entity_id=".$category_id;

        $l1Data=$connection->fetchAll($l1Query);
        $l2Data=$connection->fetchAll($l2Query);
        $l3Data=$connection->fetchAll($l3Query);
        $l4Data=$connection->fetchAll($l4Query);
        return array($l1Data,$l2Data,$l3Data,$l4Data);
     }

Please modify the above code as per your need.
Thanks
Vibhore

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top