Comprobando si un campo contiene una cadena

454

Estoy buscando un operador, que me permita verificar si el valor de un campo contiene una cadena determinada.

Algo como:

db.users.findOne({$contains:{"username":"son"}})

¿Es eso posible?

johnny
fuente

Respuestas:

693

Puedes hacerlo con el siguiente código.

db.users.findOne({"username" : {$regex : ".*son.*"}});
Parvin Gasimzade
fuente
16
Tenga en cuenta que esto no hará un uso eficiente de un índice y dará como resultado que se escaneen todos los valores en busca de coincidencias. Ver las notas sobre Expresiones regulares
Stennie
77
@Stennie, entonces, ¿qué sugieres para hacer un uso eficiente del índice y encontrar una subcadena?
Blue Sky
44
@Vish: si su caso de uso común es la búsqueda de texto libre de un campo y tiene una gran cantidad de documentos, tokenizaría el texto para consultas más eficientes. Podrías usar multikeys para una búsqueda simple de texto completo, o tal vez construir un índice invertido como una colección separada. Para búsquedas poco frecuentes o una pequeña colección de documentos, escanear el índice completo puede ser un rendimiento aceptable (aunque no óptimo).
Stennie
98
¿No es esto una exageración? Lo que quieres es db.users.findOne({"username" : {$regex : "son"}});
JamieJag
3
Es posible que desee consultar la búsqueda de texto completo en Mongo 2.6
wprl
179

Como Mongo shell admite regex, eso es completamente posible.

db.users.findOne({"username" : /.*son.*/});

Si queremos que la consulta no distinga entre mayúsculas y minúsculas, podemos usar la opción "i", como se muestra a continuación:

db.users.findOne({"username" : /.*son.*/i});

Ver: http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-RegularExpressions

James Gan
fuente
1
Incluya un fragmento de código que demuestre el uso de expresiones regulares para la búsqueda. Las respuestas deben incluir más información que un simple enlace ...
maerics
1
La respuesta seleccionada no funcionó para mí, pero esta sí (estoy ejecutando consultas mongo a través de los comandos de Docker Exec) Creo que esta debería ser la respuesta seleccionada porque parece ser más versátil.
Arthur Weborg
55
como los comentarios en la respuesta seleccionada, creo db.users.findOne({"username" : /.*son.*/});que también podría ser exagerado y la expresión regular podría ser simple/son/
Arthur Weborg
2
Forma
44
Edite esto para usarlo solo{ username: /son/ }
Wyck
150

https://docs.mongodb.com/manual/reference/sql-comparison/

http://php.net/manual/en/mongo.sqltomongo.php

MySQL

SELECT * FROM users WHERE username LIKE "%Son%"

MongoDB

db.users.find({username:/Son/})
Zheng Kai
fuente
8
Su respuesta MongoDB es buena; considere editar su pregunta para eliminar los consejos irrelevantes de MySQL.
Maerics
31
¿Eliminar todas las consultas o cambiarlas? SQL más conocido, es útil para comprender MongoDB
Zheng Kai
44
@ZhengKai: en este sitio web, por lo general, debe responder la pregunta directamente, utilizando solo las tecnologías específicas etiquetadas y solicitadas.
Maerics
98
@maerics personalmente encontré que la inclusión de MySQL de Zheng fue muy útil ya que proporcionaba un punto de referencia.
Mike Bartlett
50
También encontré relevante la referencia SQL, creo que debería permanecer.
vikingsteve
69

A partir de la versión 2.4, puede crear un índice de texto en los campos para buscar y usar el operador $ text para realizar consultas.

Primero, cree el índice:

db.users.createIndex( { "username": "text" } )

Luego, para buscar:

db.users.find( { $text: { $search: "son" } } )

Puntos de referencia (~ 150K documentos):

  • Regex (otras respuestas) => 5.6-6.9 segundos
  • Búsqueda de texto => .164-.201 segundos

Notas:

  • Una colección solo puede tener un índice de texto. Puede utilizar un índice de texto comodín si desea buscar en cualquier campo de cadena, así: db.collection.createIndex( { "$**": "text" } ).
  • Un índice de texto puede ser grande. Contiene una entrada de índice para cada palabra post-raíz única en cada campo indexado para cada documento insertado.
  • La creación de un índice de texto tardará más que un índice normal.
  • Un índice de texto no almacena frases o información sobre la proximidad de las palabras en los documentos. Como resultado, las consultas de frases se ejecutarán de manera mucho más efectiva cuando toda la colección encaje en la RAM.
okoboko
fuente
14
no, el operador de texto de hecho no permite ejecutar "contiene", por lo que solo devolverá la coincidencia exacta de palabras, la única opción actualmente a partir de 3.0 es usar regex, es decir, db.users.find ({nombre de usuario: / son / i} ) éste looksup cada usuario que contiene "hijo" (caso-insenstive)
comeGetSome
3
¿Tiene que reindexar cuando agrega o elimina documentos a / de la colección?
Jake Wilson
El título de la pregunta dice "contiene". la búsqueda de texto completo no es aplicable a la pregunta.
Donato
29

Como este es uno de los primeros éxitos en los motores de búsqueda, y ninguno de los anteriores parece funcionar para MongoDB 3.x, aquí hay una búsqueda de expresiones regulares que funciona:

db.users.find( { 'name' : { '$regex' : yourvalue, '$options' : 'i' } } )

No es necesario crear un índice adicional o similar.

Nitai
fuente
1
Las expresiones regulares necesitan ser desinfectadas.
sean
16

Esto es lo que debe hacer si está conectando MongoDB a través de Python

db.users.find({"username": {'$regex' : '.*' + 'Son' + '.*'}})

También puede usar un nombre de variable en lugar de 'Hijo' y, por lo tanto, la concatenación de cadenas.

Patthebug
fuente
en es2015 puede usar los backticks {$ regex: .*${value}.*}
Michael Guild
16

La forma más sencilla de realizar esta tarea

Si desea que la consulta distinga entre mayúsculas y minúsculas

db.getCollection("users").find({'username':/Son/})

Si desea que la consulta no distinga entre mayúsculas y minúsculas

db.getCollection("users").find({'username':/Son/i})
Anurag Misra
fuente
1
¿Cómo usar variable con regex?
Hisham
4

respuesta ideal su índice de uso i opción para mayúsculas y minúsculas

db.users.findOne({"username" : new RegExp(search_value, 'i') });
Hisham
fuente
Las expresiones regulares necesitan ser desinfectadas.
sean
2

Esto debería hacer el trabajo

db.users.find({ username: { $in: [ /son/i ] } });

El isolo está allí para evitar restricciones de coincidencia de casos individuales de letras.

Puede consultar la documentación de $ regex en la documentación de MongoDB. Aquí hay un enlace: https://docs.mongodb.com/manual/reference/operator/query/regex/

tate
fuente
1

Cómo ignorar las etiquetas HTML en una coincidencia RegExp:

var text = '<p>The <b>tiger</b> (<i>Panthera tigris</i>) is the largest <a href="https://stackoverflow.com/wiki/Felidae" title="Felidae">cat</a> <a href="https://stackoverflow.com/wiki/Species" title="Species">species</a>, most recognizable for its pattern of dark vertical stripes on reddish-orange fur with a lighter underside. The species is classified in the genus <i><a href="https://stackoverflow.com/wiki/Panthera" title="Panthera">Panthera</a></i> with the <a href="https://stackoverflow.com/wiki/Lion" title="Lion">lion</a>, <a href="https://stackoverflow.com/wiki/Leopard" title="Leopard">leopard</a>, <a href="https://stackoverflow.com/wiki/Jaguar" title="Jaguar">jaguar</a>, and <a href="https://stackoverflow.com/wiki/Snow_leopard" title="Snow leopard">snow leopard</a>. It is an <a href="https://stackoverflow.com/wiki/Apex_predator" title="Apex predator">apex predator</a>, primarily preying on <a href="https://stackoverflow.com/wiki/Ungulate" title="Ungulate">ungulates</a> such as <a href="https://stackoverflow.com/wiki/Deer" title="Deer">deer</a> and <a href="https://stackoverflow.com/wiki/Bovid" class="mw-redirect" title="Bovid">bovids</a>.</p>';
var searchString = 'largest cat species';

var rx = '';
searchString.split(' ').forEach(e => {
  rx += '('+e+')((?:\\s*(?:<\/?\\w[^<>]*>)?\\s*)*)';
});

rx = new RegExp(rx, 'igm');

console.log(text.match(rx));

Probablemente sea muy fácil convertirlo en un filtro de agregación MongoDB.

Tamás Polgár
fuente