MongoDB:¿Es posible realizar una consulta que no distinga entre mayúsculas y minúsculas?

StackOverflow https://stackoverflow.com/questions/1863399

  •  16-09-2019
  •  | 
  •  

Pregunta

Ejemplo:

> db.stuff.save({"foo":"bar"});

> db.stuff.find({"foo":"bar"}).count();
1
> db.stuff.find({"foo":"BAR"}).count();
0
¿Fue útil?

Solución

Se puede usar un expresiones regulares .

En el ejemplo que sería:

db.stuff.find( { foo: /^bar$/i } );

Debo decir, sin embargo, tal vez usted podría apenas downcase (o upcase) el valor de la manera en lugar de incurrir en el coste extra cada vez que lo encuentras. Obviamente, esto no trabajará para los nombres de las personas y tal, pero tal vez casos de uso como etiquetas.

Otros consejos

ACTUALIZACIÓN:

La respuesta original es ahora obsoleto. mongodb ahora soporta avanzados búsqueda de texto completo, con muchas características.

RESPUESTA ORIGINAL:

Debe tenerse en cuenta que la búsqueda con el caso de expresiones regulares insensibles / i significa que mongodb no se puede buscar por el índice, por lo que las consultas en grandes conjuntos de datos pueden tardar mucho tiempo.

A pesar de los pequeños conjuntos de datos, que no es muy eficiente. Se toma una CPU mucho más grande golpear que sus órdenes de consulta, lo que podría convertirse en un problema si usted está tratando de lograr escala.

Como alternativa, puede almacenar una copia en mayúsculas y la búsqueda en contra de eso. Por ejemplo, tengo una tabla de usuario que tiene un nombre de usuario que se mezcla caso, pero la identificación es una copia mayúscula del nombre de usuario. Esto asegura la duplicación entre mayúsculas y minúsculas es imposible (que tiene tanto "Foo" y "foo" no será permitido), y puedo buscar por id = username.toUpperCase () para obtener una búsqueda sensible a las mayúsculas para el nombre de usuario.

Si el campo es grande, como un cuerpo de mensaje, la duplicación de datos no es probablemente una buena opción. Creo utilizando un indexador extraños como Apache Lucene es la mejor opción en este caso.

Tenga en cuenta que el ejemplo anterior:

db.stuff.find( { foo: /bar/i } );

hará que cada entradas que contiene bar para que coincida con la consulta (Bar1, barxyz, Openbar), podría ser muy peligroso para una búsqueda de nombre de usuario en una función de autenticación ...

Es posible que necesite hacer que coincida con sólo el término de búsqueda mediante el uso de la sintaxis de expresiones regulares apropiados como:

db.stuff.find( { foo: /^bar$/i } );

http://www.regular-expressions.info/ para la ayuda de sintaxis de expresiones regulares

Si es necesario crear la expresión regular de una variable, esta es una mejor manera de hacerlo: https: // stackoverflow. com / a / 10728069/309514

A continuación, puede hacer algo como:

var string = "SomeStringToFind";
var regex = new RegExp(["^", string, "$"].join(""), "i");
// Creates a regex of: /^SomeStringToFind$/i
db.stuff.find( { foo: regex } );

Esto tiene la ventaja estar siendo más programático, o puede generar un aumento de rendimiento mediante la compilación antes de tiempo si usted está reutilizando mucho.

A partir de MongoDB, la forma recomendada para realizar búsquedas rápidas entre mayúsculas y minúsculas es utilizar un Caso Índice Insensible .

Yo personalmente enviado por correo electrónico a uno de los fundadores de complacer a conseguir este trabajo, y lo hizo así! Fue cuestión de un en JIRA desde 2009 , y muchos han pedido a la función. He aquí cómo funciona:

Un índice de mayúsculas y minúsculas se hace mediante la especificación de un intercalación con una fuerza de 1 o 2. Se puede crear un índice entre mayúsculas y minúsculas como esto:

db.cities.createIndex(
  { city: 1 },
  { 
    collation: {
      locale: 'en',
      strength: 2
    }
  }
);

También puede especificar una intercalación predeterminada por recogida cuando se crea ellas:

db.createCollection('cities', { collation: { locale: 'en', strength: 2 } } );

En cualquier caso, con el fin de utilizar el índice de mayúsculas y minúsculas, es necesario especificar la misma intercalación en la operación find que se utilizó al crear el índice o la colección:

db.cities.find(
  { city: 'new york' }
).collation(
  { locale: 'en', strength: 2 }
);

Esto devolverá "Nueva York", "Nueva York", "Nueva York", etc.

Otras notas

  • Las respuestas que sugieren utilizar búsqueda de texto completo se equivocan en este caso (y potencialmente peligroso ). La pregunta era acerca de hacer una consulta entre mayúsculas y minúsculas, por ejemplo username: 'bill' BILL coincidente o Bill, no una consulta de búsqueda de texto completo, que también se correspondería con provino palabras de bill, tales como Bills, billed etc.
  • Las respuestas que sugieren utilizar expresiones regulares son lentos, porque incluso con índices, el documentación indica :

      

    "mayúsculas y minúsculas consultas de expresiones regulares en general, no pueden utilizar los índices de eficacia. La aplicación $ regex no es colación-conscientes y es incapaz de utilizar índices entre mayúsculas y minúsculas."

    $regex respuestas también corren el riesgo de usuario inyección de entrada .

db.zipcodes.find({city : "NEW YORK"}); // Case-sensitive
db.zipcodes.find({city : /NEW york/i}); // Note the 'i' flag for case-insensitivity

TL;DR

Manera correcta de hacer esto en mongo.

No utilice ExpReg

Vaya natural y utilice la indexación y búsqueda incorporadas de mongodb

Paso 1 :

db.articles.insert(
   [
     { _id: 1, subject: "coffee", author: "xyz", views: 50 },
     { _id: 2, subject: "Coffee Shopping", author: "efg", views: 5 },
     { _id: 3, subject: "Baking a cake", author: "abc", views: 90  },
     { _id: 4, subject: "baking", author: "xyz", views: 100 },
     { _id: 5, subject: "Café Con Leche", author: "abc", views: 200 },
     { _id: 6, subject: "Сырники", author: "jkl", views: 80 },
     { _id: 7, subject: "coffee and cream", author: "efg", views: 10 },
     { _id: 8, subject: "Cafe con Leche", author: "xyz", views: 10 }
   ]
)

Paso 2 :

Necesidad de crear un índice sobre lo que sea TEXTO El campo que desea buscar, sin indexación, la consulta será extremadamente lenta.

db.articles.createIndex( { subject: "text" } )

paso 3 :

db.articles.find( { $text: { $search: "coffee",$caseSensitive :true } } )  //FOR SENSITIVITY
db.articles.find( { $text: { $search: "coffee",$caseSensitive :false } } ) //FOR INSENSITIVITY
db.company_profile.find({ "companyName" : { "$regex" : "Nilesh" , "$options" : "i"}});

Mongo (versión actual 2.0.0) no permite búsquedas mayúsculas y minúsculas contra campos indexados - ver su documentación. Para los campos no indexados, las expresiones regulares que figuran en las otras respuestas deben estar bien.

El mejor método es en el idioma de su elección, al crear un modelo de envoltorio para sus objetos, haga que su método Save () repetición de un conjunto de campos que se le realizan búsquedas en que también están en el índice; los conjunto de campos deben tener las minúsculas que se utilizan a continuación para la búsqueda.

Cada vez que el objeto se guarda de nuevo, las propiedades minúsculas se revisan y se actualiza con los cambios en las propiedades principales. Esto hará que sea para que pueda buscar de manera eficiente, pero ocultar el trabajo extra que se necesita para actualizar los campos lc cada vez.

Los campos minúsculas podrían ser una clave: almacén de objetos de valor o simplemente el nombre del campo con un LC_ prefijado. Utilizo el segundo uno para simplificar la consulta (consulta objeto profunda puede ser confuso a veces).

Nota: desea indexar los campos LC_, no de los principales campos que se basan fuera de.

Supongamos que desea buscar "columna" en la "Tabla" y desea caso insenstive búsqueda. La mejor y más eficiente es la siguiente;

//create empty JSON Object
mycolumn = {};

//check if column has valid value
if(column) {
    mycolumn.column = {$regex: new RegExp(column), $options: "i"};
}
Table.find(mycolumn);

Por encima de código sólo se suma a su valor de búsqueda como expresiones regulares y búsquedas con criterios establecidos Insensible con "i" como opción.

Todo lo mejor.

Una cosa muy importante a tener en cuenta al utilizar una consulta basada Regex - Cuando usted está haciendo esto para un sistema de inicio de sesión, escapar cada personaje que está buscando, y no se olvide el ^ $ y operadores. Lodash tiene una función agradable para este , en caso de que esté utilizando ya:

db.stuff.find({$regex: new RegExp(_.escapeRegExp(bar), $options: 'i'})

¿Por qué? Imagine un usuario que entra .* como su nombre de usuario. Que coincidiría con todos los nombres de usuario, lo que permite un inicio de sesión con sólo adivinar la contraseña de cualquier usuario.

El uso de la mangosta esto funcionó para mí:

var find = function(username, next){
    User.find({'username': {$regex: new RegExp('^' + username, 'i')}}, function(err, res){
        if(err) throw err;
        next(null, res);
    });
}

El marco agregación se introdujo en mongodb 2.2. Se puede utilizar el operador de cadena "$ strcasecmp" para hacer una comparación entre mayúsculas y minúsculas entre las cuerdas. Es más recomendable y más fácil de utilizar expresiones regulares.

Este es el documento oficial en el comando del operador de agregación: https://docs.mongodb.com/manual/reference/operator/aggregation/strcasecmp/#exp._S_strcasecmp .

Puede utilizar Casos índices Insensible

En el siguiente ejemplo se crea una colección sin intercalación predeterminada, a continuación, añade un índice en el campo de nombre con una intercalación insensibles. Componentes internacionales para Unicode

/* strength: CollationStrength.Secondary
* Secondary level of comparison. Collation performs comparisons up to secondary * differences, such as diacritics. That is, collation performs comparisons of 
* base characters (primary differences) and diacritics (secondary differences). * Differences between base characters takes precedence over secondary 
* differences.
*/
db.users.createIndex( { name: 1 }, collation: { locale: 'tr', strength: 2 } } )

Para utilizar el índice, las consultas deben especificar la misma intercalación.

db.users.insert( [ { name: "Oğuz" },
                            { name: "oğuz" },
                            { name: "OĞUZ" } ] )

// does not use index, finds one result
db.users.find( { name: "oğuz" } )

// uses the index, finds three results
db.users.find( { name: "oğuz" } ).collation( { locale: 'tr', strength: 2 } )

// does not use the index, finds three results (different strength)
db.users.find( { name: "oğuz" } ).collation( { locale: 'tr', strength: 1 } )

o puede crear una colección con colación por defecto:

db.createCollection("users", { collation: { locale: 'tr', strength: 2 } } )
db.users.createIndex( { name : 1 } ) // inherits the default collation

En la búsqueda de una variable y de otra:

const escapeStringRegexp = require('escape-string-regexp')
const name = 'foo'
db.stuff.find({name: new RegExp('^' + escapeStringRegexp(name) + '$', 'i')})   

Escapar de la variable protege la consulta contra ataques con '*' u otra expresión regular.

escapar cuerdas-regexp

He creado un simple Func para el caso de expresiones regulares insensibles, que yo uso en mi filtro.

private Func<string, BsonRegularExpression> CaseInsensitiveCompare = (field) => 
            BsonRegularExpression.Create(new Regex(field, RegexOptions.IgnoreCase));

Entonces sólo tiene que filtrar en un campo de la siguiente manera.

db.stuff.find({"foo": CaseInsensitiveCompare("bar")}).count();

El uso de un filtro funciona para mí en C #.

string s = "searchTerm";
    var filter = Builders<Model>.Filter.Where(p => p.Title.ToLower().Contains(s.ToLower()));
                var listSorted = collection.Find(filter).ToList();
                var list = collection.Find(filter).ToList();

Se puede incluso utilizar el índice porque creo que los métodos se llaman después de la vuelta pasa, pero no he probado, sin embargo.

Esto también evita un problema de

var filter = Builders<Model>.Filter.Eq(p => p.Title.ToLower(), s.ToLower());

mongodb que pensarán p.Title.ToLower () es una propiedad y no asignar correctamente.

Para cualquiera usando Golang y desea tener el caso de búsqueda sensible a texto completo con MongoDB y el MgO godoc GlobalSign biblioteca .

collation := &mgo.Collation{
    Locale:   "en",
    Strength: 2, 
}


err := collection.Find(query).Collation(collation)

Uso RegExp  En caso de que cualquier otra opción no funcionan para usted, RegExp es una buena opción. Esto hace que la cadena caso insensible.

var username = new RegExp("^" + "John" + "$", "i");;

utilizar nombre de usuario en las consultas, y luego se hace.

Espero que trabajará para usted también. Todo lo mejor.

Como se puede ver en la documentación mongo - desde el índice de la versión 3.2 $text es sensible a las mayúsculas por defecto: https://docs.mongodb.com/manual/core/index-text/#text-index-case-insensitivity

crear un índice de texto y < a href = "https://docs.mongodb.com/manual/reference/operator/query/text/#op._S_text" rel = "nofollow noreferrer"> uso $ operador de texto en la consulta .

Estos han sido probados para la búsqueda de cadenas

{'_id': /.*CM.*/}               ||find _id where _id contains   ->CM
{'_id': /^CM/}                  ||find _id where _id starts     ->CM
{'_id': /CM$/}                  ||find _id where _id ends       ->CM

{'_id': /.*UcM075237.*/i}       ||find _id where _id contains   ->UcM075237, ignore upper/lower case
{'_id': /^UcM075237/i}          ||find _id where _id starts     ->UcM075237, ignore upper/lower case
{'_id': /UcM075237$/i}          ||find _id where _id ends       ->UcM075237, ignore upper/lower case

Me había enfrentado a un problema similar y esto es lo que funcionó para mí:

  const flavorExists = await Flavors.findOne({
    'flavor.name': { $regex: flavorName, $options: 'i' },
  });
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top