Filtrar resultados usando LIKE

16

Considere estas tres cadenas de "pajar":

un) foo bar

si) welcome to foo bar industries

C) foo barer

Y ahora mi "aguja":

foo bar

(Je)

Me gustaría que mi filtro haga coincidir mi aguja con las cadenas de pajar a & b pero no c. Yo he tratado:

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

Pero lo anterior coincide con c.

También probé:

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

Lo anterior solo coincide con b.

Cualquier ayuda es muy apreciada.

siendoalex
fuente

Respuestas:

37

Intente esto y vea si encaja:

$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
));

Pasar el segundo parámetro como una matriz de matrices concatenará las condiciones usando OR

Marius
fuente
Eso funciona :) No sabía sobre el truco de la matriz, gracias.
beingalex
Con modelos personalizados / no eav se addAttributeToFilterdeben reemplazar con addFieldToFilter.
jvalanen
¿Hay alguna manera de determinar qué matriz devolvió un resultado? Estoy usando este método para buscar en una colección de modelos personalizados (nombre, descripción, campos de nombre alternativo) y me gustaría saber si el resultado se alcanzó debido a la descripción (para incluir un elemento de IU adicional en los resultados de búsqueda).
pspahn
3
@pspahn No es sencillo. Puede recorrer los resultados después de ejecutar la selección y verificar si la aguja se encuentra en alguno de los campos que desea.
Marius
9

Una posible solución es usar en REGEXPlugar de LIKE:

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

De la documentación de MySQL :

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

Estos marcadores representan límites de palabras. Coinciden con el principio y el final de las palabras, respectivamente. Una palabra es una secuencia de caracteres de palabras que no está precedida o seguida de caracteres de palabras. Un carácter de palabra es un carácter alfanumérico en la clase alnum o un guión bajo (_).

Tenga en cuenta que si $needlepuede contener caracteres que tienen significados especiales en las expresiones regulares POSIX, debe escapar de ellos. Ver también: /programming/4024188/php-function-to-escape-mysql-regexp-syntax

Fabian Schmengler
fuente
3

La respuesta aceptada no funciona correctamente. Está comprobando solo el espacio antes y después del texto.

Supongamos que tienes la siguiente lista

  • Chaqueta
  • Chaqueta de verano
  • Chaqueta de invierno

Ahora, si intentas buscar con la chaqueta con la respuesta aceptada, solo se mostrarán Summer Jacket y Winter Jacket

Creo que la siguiente solución es mejor

$collection->addAttributeToFilter('name', array('like' => '%' . $needle. '%'));
Dinesh Yadav
fuente
No cubriría el caso (c) de la pregunta (es decir, también coincidiría con "camisa"). En cambio, se ['eq' => $needle]podría agregar una cuarta condición para encontrar coincidencias exactas (o mejor, usar la solución regex que encuentra todos los límites, no solo los espacios)
Fabian Schmengler
El código anterior puede encontrar las coincidencias exactas. Lo revisé
Dinesh Yadav
No lo dudo. Pero encuentra más, que no debería. Al menos si tiene los mismos requisitos que en la pregunta original: No encuentre "foo barer" cuando busque "foo bar"
Fabian Schmengler
Sí, tiene usted razón. La respuesta aceptada no funcionaba correctamente para mí, así que sugerí el filtro simple de una línea para obtener los elementos similares.
Dinesh Yadav