Magento addFieldToFilter: два поля, соответствующие ИЛИ, а не И

Я застрял на этом в течение последних нескольких часов. Я заставил его работать, взломав несколько строк в /lib/Varien/Data/Collection/Db.php, но я бы предпочел использовать правильное решение и оставить свое ядро ​​​​нетронутым.

Все, что мне нужно сделать, это получить коллекцию и отфильтровать ее по двум или более полям. Скажем, customer_firstname и remote_ip. Вот мой (неработоспособный без взлома Db.php) код:

$collection = Mage::getModel('sales/order')->getCollection()->
addAttributeToSelect("*")->
addFieldToFilter(array(array('remote_ip', array('eq'=>'127.0.0.1')),
array('customer_firstname', array('eq'=>'gabe'))), array('eq'=>array(1,2,3)));

С запасом Db.php я попробовал это: (образец взят с http://magentoexpert.blogspot.com/2009/12/retrieve-products-with-specific.html)

$collection->addFieldToFilter(array(
    array('name'=>'orig_price','eq'=>'Widget A'),
    array('name'=>'orig_price','eq'=>'Widget B'),           
));

Но это дает мне эту ошибку:

Warning: Illegal offset type in isset or empty  in magento/lib/Varien/Data/Collection/Db.php on line 369

Если я оберну это с помощью try/catch, то он переместится в _getConditionSql() и выдаст эту ошибку:

Warning: Invalid argument supplied for foreach()  in magento/lib/Varien/Data/Collection/Db.php on line 412

У кого-нибудь есть рабочий, функциональный код для этого? Я использую Magento 1.9 (предприятие). Спасибо!


person Gabriel H    schedule 29.09.2010    source источник


Ответы (10)


У меня есть другой способ добавить условие or в поле:

->addFieldToFilter(
    array('title', 'content'),
    array(
        array('like'=>'%$titlesearchtext%'), 
        array('like'=>'%$contentsearchtext%')
    )
)
person Riyazkhan    schedule 21.10.2011
comment
Я пробовал все ответы, и это единственный ответ, который сработал для меня. Ответ Анды для OR заключался в попытке поиска атрибута под названием «атрибут», поэтому я продолжал получать ошибки неизвестного столбца «атрибут». В других решениях были правильные имена столбцов, но не было значений. Это дало мне правильные результаты в SQL: ... WHERE (('first_attribute' = 'some value') OR ('second_attribute' = 'some value')) - person BrianVPS; 29.05.2012
comment
Пытаясь таким образом, я получаю столбец не найден: 1054 Неизвестный столбец «Массив» в «где пункт» ошибка - person zuzuleinen; 23.07.2013
comment
обратите внимание, что этот синтаксис неверен для addAttributeToFilter, см. stackoverflow.com/a/5301457/3338098 для этого синтаксиса - person user3338098; 14.07.2016

Условия ИЛИ могут быть сгенерированы следующим образом:

$collection->addFieldToFilter(
    array('field_1', 'field_2', 'field_3'), // columns
    array( // conditions
        array( // conditions for field_1
            array('in' => array('text_1', 'text_2', 'text_3')),
            array('like' => '%text')
        ),
        array('eq' => 'exact'), // condition for field 2
        array('in' => array('val_1', 'val_2')) // condition for field 3
    )
);

Это создаст условие SQL WHERE примерно так:

... WHERE (
         (field_1 IN ('text_1', 'text_2', 'text_3') OR field_1 LIKE '%text')
      OR (field_2 = 'exact')
      OR (field_3 IN ('val_1', 'val_2'))
    )

Каждый вложенный массив (‹условие›) генерирует другой набор скобок для условия ИЛИ.

person CJ Dennis    schedule 20.03.2013
comment
Причина, по которой это работает, заключается в том, что он использует ключи в первом параметре (массиве полей) для поиска значения во втором параметре (массиве условий) для использования в этом поле. Я считаю, что немного понятнее сделать что-то вроде: $collection->addFieldToFilter( array('field_1'=>'field_1', 'field_2'=>'field_2'), array( 'field_1'=>array( array('in' => array('text_1', 'text_2', 'text_3'), array('like' => '%text') ), 'field_2'=>array('eq' => 'exact'), ) ); - person Ariel Allon; 06.11.2014
comment
Этот фильтр фактически работал для условий ИЛИ. Спасибо! - person Corgalore; 12.01.2015
comment
обратите внимание, что этот синтаксис неверен для addAttributeToFilter, обратитесь к stackoverflow.com/a/5301457/3338098 для этого синтаксиса - person user3338098; 14.07.2016

Я также пытался получить field1 = 'a' OR field2 = 'b'

Ваш код у меня не сработал.

Вот мое решение

$results = Mage::getModel('xyz/abc')->getCollection();
$results->addFieldToSelect('name');
$results->addFieldToSelect('keywords');
$results->addOrder('name','ASC');
$results->setPageSize(5);

$results->getSelect()->where("keywords like '%foo%' or additional_keywords  like '%bar%'");

$results->load();

echo json_encode($results->toArray());

Это дает мне

SELECT name, keywords FROM abc WHERE keywords like '%foo%' OR additional_keywords like '%bar%'.

Возможно, это не «путь magento», но я застрял на этом 5 часов.

Надеюсь, это поможет

person user654539    schedule 11.03.2011
comment
Это также лучшее решение, которое я знаю - person zuzuleinen; 23.07.2013
comment
Я пытался заставить сложный запрос работать с пользовательскими моделями ресурсов уже несколько часов. Вот что наконец сработало. Спасибо. - person billmalarky; 04.09.2014

Вот мое решение в Enterprise 1.11 (должно работать в CE 1.6):

    $collection->addFieldToFilter('max_item_count',
                    array(
                        array('gteq' => 10),
                        array('null' => true),
                    )
            )
            ->addFieldToFilter('max_item_price',
                    array(
                        array('gteq' => 9.99),
                        array('null' => true),
                    )
            )
            ->addFieldToFilter('max_item_weight',
                    array(
                        array('gteq' => 1.5),
                        array('null' => true),
                    )
            );

Что приводит к этому SQL:

    SELECT `main_table`.*
    FROM `shipping_method_entity` AS `main_table`
    WHERE (((max_item_count >= 10) OR (max_item_count IS NULL)))
      AND (((max_item_price >= 9.99) OR (max_item_price IS NULL)))
      AND (((max_item_weight >= 1.5) OR (max_item_weight IS NULL)))
person Michael Payne    schedule 20.07.2012

Для фильтрации по нескольким атрибутам используйте что-то вроде:

//for AND
    $collection = Mage::getModel('sales/order')->getCollection()
    ->addAttributeToSelect('*')
    ->addFieldToFilter('my_field1', 'my_value1')
    ->addFieldToFilter('my_field2', 'my_value2');

    echo $collection->getSelect()->__toString();

//for OR - please note 'attribute' is the key name and must remain the same, only replace //the value (my_field1, my_field2) with your attribute name


    $collection = Mage::getModel('sales/order')->getCollection()
        ->addAttributeToSelect('*')
        ->addFieldToFilter(
            array(
                array('attribute'=>'my_field1','eq'=>'my_value1'),
                array('attribute'=>'my_field2', 'eq'=>'my_value2')
            )
        );

Для получения дополнительной информации проверьте: http://docs.magentocommerce.com/Varien/Varien_Data/Varien_Data_Collection_Db.html#_getConditionSql

person Anda B    schedule 30.09.2010
comment
Спасибо, Анда. Но это для требования обоих полей, а не одного или другого. Если вы добавите -›getSelectSql() в конец этого запроса, это даст вам ... ГДЕ (my_field1 = 'my_value1') AND (my_field2 = 'my_value2'). Я пытаюсь получить ГДЕ (myfield1 = 'myvalue1') ИЛИ (myfield2 = 'myvalue2'). - person Gabriel H; 30.09.2010
comment
Это работает только с addAttributeToFilter в коллекциях EAV. Ответ Риязхана правильный. - person rterrani; 05.08.2012

Спасибо, Анда, твой пост очень помог!! Однако предложение ИЛИ не совсем сработало для меня, и я получил сообщение об ошибке: getCollection() "недопустимый аргумент для foreach".

Итак, вот что я закончил (обратите внимание, что атрибут указан 3 раза вместо 2 в этом случае):

  $collection->addFieldToFilter('attribute', array(  
    array('attribute'=>'my_field1','eq'=>'my_value1'),            
    array('attribute'=>'my_field2','eq'=>'my_value2') ));

Для addFieldToFilter сначала требуется поле, а затем условие -> ссылка.

person jazkat    schedule 13.05.2011
comment
+1 за это. @решение Анды неверно для условия ИЛИ. - person leek; 15.07.2011

Здесь происходит небольшая путаница, но позвольте мне попытаться прояснить ситуацию:

Допустим, вы хотели, чтобы sql выглядел примерно так:

SELECT 
    `main_table`.*, 
    `main_table`.`email` AS `invitation_email`, 
    `main_table`.`group_id` AS `invitee_group_id` 
FROM 
    `enterprise_invitation` AS `main_table` 
WHERE (
    (status = 'new') 
    OR (customer_id = '1234')
)

Для этого ваша коллекция должна быть отформатирована следующим образом:

$collection = Mage::getModel('enterprise_invitation/invitation')->getCollection();

$collection->addFieldToFilter(array('status', 'customer_id'), array(
array('status','eq'=>'new'),
array('customer_id', 'eq'=>'1234') ));

Теперь, чтобы увидеть, как это выглядит, вы всегда можете повторить запрос, который это создает, используя

echo $collection->getSelect()->__toString();
person phpCodeNinja    schedule 19.12.2012

Это настоящий способ magento:

    $collection=Mage::getModel('sales/order')
                ->getCollection()
                ->addFieldToFilter(
                        array(
                            'customer_firstname',//attribute_1 with key 0
                            'remote_ip',//attribute_2 with key 1
                        ),
                        array(
                            array('eq'=>'gabe'),//condition for attribute_1 with key 0
                            array('eq'=>'127.0.0.1'),//condition for attribute_2
                                )
                            )
                        );
person Gabriel    schedule 03.06.2013

public function testAction()
{
        $filter_a = array('like'=>'a%');
        $filter_b = array('like'=>'b%');
        echo(
        (string) 
        Mage::getModel('catalog/product')
        ->getCollection()
        ->addFieldToFilter('sku',array($filter_a,$filter_b))
        ->getSelect()
        );
}

Результат:

WHERE (((e.sku like 'a%') or (e.sku like 'b%')))

Источник: http://alanstorm.com/magento_collections

person De Nguyen    schedule 10.07.2015

Чтобы создать простое условие ИЛИ для коллекции, используйте следующий формат:

    $orders = Mage::getModel('sales/order')->getResourceCollection();
    $orders->addFieldToFilter(
      'status',
      array(
        'processing',
        'pending',
      )
    );

Это создаст SQL следующим образом:

WHERE (((`status` = 'processing') OR (`status` = 'pending')))
person XPS    schedule 06.09.2016