Uma observação para todos que tentarem usar uma resposta envolvendo regexes: Regexes precisam ser higienizados.
sean
Respostas:
128
A solução de Chris Fulstow funcionará (+1), entretanto, pode não ser eficiente, especialmente se sua coleção for muito grande. Expressões regulares não enraizadas (aquelas que não começam com ^, que ancoram a expressão regular no início da string) e aquelas que usam o isinalizador para insensibilidade a maiúsculas e minúsculas não usarão índices, mesmo se eles existirem.
Uma opção alternativa que você pode considerar é desnormalizar seus dados para armazenar uma versão em minúsculas do namecampo, por exemplo como name_lower. Você pode então consultar isso de forma eficiente (especialmente se for indexado) para correspondências exatas que não diferenciam maiúsculas de minúsculas como:
Ótima resposta, minha abordagem regex realmente fica mais lenta, uma vez que precisa digitalizar alguns milhões de documentos.
Chris Fulstow
35
Na verdade, isso não está totalmente correto, porque você pode encontrar "Andrew alguma coisa" enquanto procura por "Andrew". Portanto, ajuste o regex para: new RegExp('^'+ username + '$', "i")para ser uma correspondência exata.
Tarion de
9
De acordo com o site do MongoDB, qualquer regex insensível a maiúsculas e minúsculas não é eficiente no índice "$ regex só pode usar um índice de forma eficiente quando a expressão regular tem uma âncora para o início (ou seja, ^) de uma string e é uma correspondência que diferencia maiúsculas de minúsculas "
Ryan Schumacher,
2
Com o Mongoose, isso funcionou para mim: User.find ({'username': {$ regex: new RegExp ('^' + username.toLowerCase (), 'i')}}, function (err, res) {if (err ) lançar err; próximo (nulo, res);});
ChrisRich
5
Nunca se esqueça de escapar do nome ao trabalhar com expressões regulares. Não queremos que as injeções controlem a beleza do mongodb. Imagine que você usou este código para uma página de login e o nome de usuário era ".*".
Tobias
91
Você precisaria usar uma expressão regular que não diferencia maiúsculas de minúsculas para este, por exemplo
O MongoDB 3.4 agora inclui a capacidade de criar um índice que não diferencia maiúsculas de minúsculas, o que aumentará drasticamente a velocidade das pesquisas que não diferenciam maiúsculas de minúsculas em grandes conjuntos de dados. É feito especificando um agrupamento com uma intensidade de 2.
Provavelmente, a maneira mais fácil de fazer isso é definir um agrupamento no banco de dados. Então, todas as consultas herdam esse agrupamento e o usarão:
Você pode usar índices que não diferenciam maiúsculas de minúsculas :
O exemplo a seguir cria uma coleção sem agrupamento padrão e, em seguida, adiciona um índice no campo de nome com um agrupamento que não diferencia maiúsculas de minúsculas. Componentes Internacionais 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 usar o índice, as consultas devem especificar o mesmo agrupamento.
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 } )
ou você pode criar uma coleção com agrupamento padrão:
As expressões regulares são mais lentas do que a correspondência de string literal. No entanto, um campo adicional em minúsculas aumentará a complexidade do código. Em caso de dúvida, use expressões regulares. Eu sugeriria usar apenas um campo explicitamente em minúsculas se ele puder substituir o seu campo, ou seja, você não se importa com o caso em primeiro lugar.
Observe que você precisará escapar do nome antes do regex. Se você quiser caracteres curinga de entrada do usuário, prefira acrescentar .replace(/%/g, '.*')depois de escapar para que possa corresponder a "a%" para encontrar todos os nomes que começam com 'a'.
Respostas:
A solução de Chris Fulstow funcionará (+1), entretanto, pode não ser eficiente, especialmente se sua coleção for muito grande. Expressões regulares não enraizadas (aquelas que não começam com
^
, que ancoram a expressão regular no início da string) e aquelas que usam oi
sinalizador para insensibilidade a maiúsculas e minúsculas não usarão índices, mesmo se eles existirem.Uma opção alternativa que você pode considerar é desnormalizar seus dados para armazenar uma versão em minúsculas do
name
campo, por exemplo comoname_lower
. Você pode então consultar isso de forma eficiente (especialmente se for indexado) para correspondências exatas que não diferenciam maiúsculas de minúsculas como:db.collection.find({"name_lower": thename.toLowerCase()})
Ou com uma correspondência de prefixo (uma expressão regular enraizada) como:
db.collection.find( {"name_lower": { $regex: new RegExp("^" + thename.toLowerCase(), "i") } } );
Ambas as consultas usarão um índice em
name_lower
.fonte
new RegExp('^'+ username + '$', "i")
para ser uma correspondência exata.".*"
.Você precisaria usar uma expressão regular que não diferencia maiúsculas de minúsculas para este, por exemplo
db.collection.find( { "name" : { $regex : /Andrew/i } } );
Para usar o padrão regex de sua
thename
variável, construa um novo objeto RegExp :var thename = "Andrew"; db.collection.find( { "name" : { $regex : new RegExp(thename, "i") } } );
Atualização: para correspondência exata, você deve usar o regex
"name": /^Andrew$/i
. Graças a Yannick L.fonte
name
, não apenas igualando.{ "name": /^Andrew$/i }
Eu resolvi assim.
var thename = 'Andrew'; db.collection.find({'name': {'$regex': thename,$options:'i'}});
Se você quiser fazer uma consulta sobre 'correspondência exata que não diferencia maiúsculas de minúsculas', pode fazer o seguinte.
var thename = '^Andrew$'; db.collection.find({'name': {'$regex': thename,$options:'i'}});
fonte
Com o Mongoose (e Node), isso funcionou:
User.find({ email: /^[email protected]$/i })
User.find({ email: new RegExp(
`^ $ {emailVariable} $`, 'i')})No MongoDB, isso funcionou:
db.users.find({ email: { $regex: /^[email protected]$/i }})
Ambas as linhas não diferenciam maiúsculas de minúsculas. O email no DB pode ser
[email protected]
e ambas as linhas ainda encontrarão o objeto no DB.Da mesma forma, poderíamos usar
/^[email protected]$/i
e ainda encontraria email:[email protected]
no DB.fonte
O MongoDB 3.4 agora inclui a capacidade de criar um índice que não diferencia maiúsculas de minúsculas, o que aumentará drasticamente a velocidade das pesquisas que não diferenciam maiúsculas de minúsculas em grandes conjuntos de dados. É feito especificando um agrupamento com uma intensidade de 2.
Provavelmente, a maneira mais fácil de fazer isso é definir um agrupamento no banco de dados. Então, todas as consultas herdam esse agrupamento e o usarão:
db.createCollection("cities", { collation: { locale: 'en_US', strength: 2 } } ) db.names.createIndex( { city: 1 } ) // inherits the default collation
Você também pode fazer assim:
db.myCollection.createIndex({city: 1}, {collation: {locale: "en", strength: 2}});
E use-o assim:
db.myCollection.find({city: "new york"}).collation({locale: "en", strength: 2});
Isso retornará cidades chamadas "nova york", "Nova York", "Nova york" etc.
Para mais informações: https://jira.mongodb.org/browse/SERVER-90
fonte
Para encontrar strings que não diferenciam maiúsculas de minúsculas, use isso,
var thename = "Andrew"; db.collection.find({"name":/^thename$/i})
fonte
Acabei de resolver esse problema há algumas horas.
var thename = 'Andrew' db.collection.find({ $text: { $search: thename } });
Você pode até mesmo expandir isso selecionando os campos necessários do objeto de usuário de Andrew, fazendo isso desta maneira:
db.collection.find({ $text: { $search: thename } }).select('age height weight');
Referência: https://docs.mongodb.org/manual/reference/operator/query/text/#text
fonte
... com mangusto em NodeJS que consulta:
const countryName = req.params.country; { 'country': new RegExp(`^${countryName}$`, 'i') };
ou
const countryName = req.params.country; { 'country': { $regex: new RegExp(`^${countryName}$`), $options: 'i' } }; // ^australia$
ou
const countryName = req.params.country; { 'country': { $regex: new RegExp(`^${countryName}$`, 'i') } }; // ^turkey$
Um exemplo de código completo em Javascript, NodeJS com Mongoose ORM no MongoDB
// get all customers that given country name app.get('/customers/country/:countryName', (req, res) => { //res.send(`Got a GET request at /customer/country/${req.params.countryName}`); const countryName = req.params.countryName; // using Regular Expression (case intensitive and equal): ^australia$ // const query = { 'country': new RegExp(`^${countryName}$`, 'i') }; // const query = { 'country': { $regex: new RegExp(`^${countryName}$`, 'i') } }; const query = { 'country': { $regex: new RegExp(`^${countryName}$`), $options: 'i' } }; Customer.find(query).sort({ name: 'asc' }) .then(customers => { res.json(customers); }) .catch(error => { // error.. res.send(error.message); }); });
fonte
Você pode usar índices que não diferenciam maiúsculas de minúsculas :
O exemplo a seguir cria uma coleção sem agrupamento padrão e, em seguida, adiciona um índice no campo de nome com um agrupamento que não diferencia maiúsculas de minúsculas. Componentes Internacionais 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 usar o índice, as consultas devem especificar o mesmo agrupamento.
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 } )
ou você pode criar uma coleção com agrupamento padrão:
db.createCollection("users", { collation: { locale: 'tr', strength: 2 } } ) db.users.createIndex( { name : 1 } ) // inherits the default collation
fonte
A consulta a seguir encontrará os documentos com a string necessária de forma insensível e com ocorrência global também
db.collection.find({name:{ $regex: new RegExp(thename, "ig") } },function(err, doc) { //Your code here... });
fonte
Para encontrar strings de literais que não diferenciam maiúsculas de minúsculas:
Usando regex (recomendado)
db.collection.find({ name: { $regex: new RegExp('^' + name.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + '$', 'i') } });
Usando índice em minúsculas (mais rápido)
db.collection.find({ name_lower: name.toLowerCase() });
As expressões regulares são mais lentas do que a correspondência de string literal. No entanto, um campo adicional em minúsculas aumentará a complexidade do código. Em caso de dúvida, use expressões regulares. Eu sugeriria usar apenas um campo explicitamente em minúsculas se ele puder substituir o seu campo, ou seja, você não se importa com o caso em primeiro lugar.
Observe que você precisará escapar do nome antes do regex. Se você quiser caracteres curinga de entrada do usuário, prefira acrescentar
.replace(/%/g, '.*')
depois de escapar para que possa corresponder a "a%" para encontrar todos os nomes que começam com 'a'.fonte
Uma maneira fácil seria usar $ toLower conforme abaixo.
db.users.aggregate([ { $project: { name: { $toLower: "$name" } } }, { $match: { name: the_name_to_search } } ])
fonte