Фильтрация результатов с использованием LIKE

16

Рассмотрим эти три строки «стог сена»:

а) foo bar

б) welcome to foo bar industries

с) foo barer

А теперь моя «игла»:

foo bar

(Хех)

Я хотел бы, чтобы мой фильтр соответствовал моей игле со строками сена a & b, но не c. Я пытался:

$collection->addAttributeToFilter('name', array('like' => '%'.$needle.'%'));

Но вышеупомянутое соответствует c.

Я также попробовал:

$collection->addAttributeToFilter('name', array('like' => '% '.$needle.' %')); // Note the spaces

Выше соответствует только с б.

Любая помощь очень ценится.

beingalex
источник

Ответы:

37

Попробуйте и посмотрите, подходит ли он:

$collection->addAttributeToFilter('name', array(
    array('like' => '% '.$needle.' %'), //spaces on each side
    array('like' => '% '.$needle), //space before and ends with $needle
    array('like' => $needle.' %') // starts with needle and space after
));

Передача второго параметра в виде массива массивов объединит условия, используя OR

Мариус
источник
Это работает :) Не знал о трюке с массивами, спасибо.
Beingalex
С нестандартными / не eav моделями addAttributeToFilterследует заменить на addFieldToFilter.
Jvalanen
Есть ли способ определить, какой массив вернул результат? Я использую этот метод для поиска в пользовательской коллекции моделей (имя, описание, поля alternate_name) и хотел бы знать, был ли достигнут результат из-за описания (чтобы включить дополнительный элемент пользовательского интерфейса в результаты поиска).
pspahn
3
@pspahn Не прямолинейный. Вы можете просмотреть результаты после выполнения выбора и проверить, находится ли стрелка в любом из полей, которые вы хотите.
Мариус
9

Возможное решение - использовать REGEXPвместо LIKE:

$collection->addAttributeToFilter('name', array('regexp' => '[[:<:]]'.$needle.'[[:>:]]'));

Из документации MySQL :

[[: <:]], [[:>:]]

Эти маркеры обозначают границы слов. Они соответствуют началу и концу слов соответственно. Слово - это последовательность символов слова, которой не предшествуют и не следуют символы слова. Символ слова - это буквенно-цифровой символ в классе alnum или знак подчеркивания (_).

Обратите внимание, что если $needleв регулярных выражениях POSIX могут содержаться символы, имеющие особое значение, вам нужно их избегать. Смотрите также: /programming/4024188/php-function-to-escape-mysql-regexp-syntax

Фабиан Шменглер
источник
3

Принятый ответ не работает должным образом. Он проверяет только пробел до и после текста.

Предположим, у вас есть следующий список

  • Куртка
  • Летняя куртка
  • Зимняя куртка

Теперь, если вы попытаетесь найти куртку, используя принятый ответ, он вернет только Summer Jacket и Winter Jacket

Я думаю, что следующее решение лучше

$collection->addAttributeToFilter('name', array('like' => '%' . $needle. '%'));
Динеш Ядав
источник
Это не будет охватывать случай (с) из вопроса (то есть также соответствовать «защитному покрытию»). Вместо этого ['eq' => $needle]может быть добавлено четвертое условие , чтобы найти точные совпадения (или, лучше, использовать решение регулярных выражений, которое находит все границы, а не только пробелы)
Фабиан Шменглер,
Код выше может найти точные совпадения. Я проверил это
Динеш Ядав
Я не сомневался в этом. Но он находит больше, чего не должен. По крайней мере, если у вас есть те же требования, что и в исходном вопросе: не находите «foo barer» при поиске «foo bar»
Фабиан Шменглер,
Да ты прав. Принятый ответ не работал для меня должным образом, поэтому я предложил простой однострочный фильтр для получения аналогичных предметов.
Динеш Ядав