Mongoose.js: Encontre o usuário pelo valor de nome de usuário LIKE

94

Eu gosto de encontrar um usuário no mongoDb procurando por um usuário chamado valor. O problema com:

username: 'peter'

é que não encontro se o nome de usuário for "Peter" ou "PeTER" .. ou algo parecido.

Então eu quero fazer como sql

SELECT * FROM users WHERE username LIKE 'peter'

Espero que vocês entendam o que estou pedindo?

Resumindo: 'campo LIKE valor' em mongoose.js / mongodb

PeterBechP
fonte
1
Apenas um aparte, a consulta SQL não encontraria Peterou PeTERporque LIKEnão faz distinção entre maiúsculas e minúsculas.
beny23,

Respostas:

143

Para quem estava procurando uma solução aqui está:

var name = 'Peter';
model.findOne({name: new RegExp('^'+name+'$', "i")}, function(err, doc) {
  //Do your action here..
});
PeterBechP
fonte
2
o que significa o argumento "i"? Tem algo a ver com a diferenciação de maiúsculas e minúsculas?
AzaFromKaza
2
"i" é um argumento para escolher um sinalizador de pesquisa. "i" então não faz distinção entre maiúsculas e minúsculas. Você pode ler mais sobre isso aqui. developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/…
PeterBechP
10
Isso pressupõe que a regex não é inválida. Se você adicionar "[" como nome de usuário, por exemplo, lançará uma exceção. Apenas certifique-se de tentar capturar ou regexar sua entrada antes e verificar se há [^ a-zA-Z0-9] e não prosseguir. Nesse caso, é apenas uma entrada de teste, então faz sentido.
Jason Sebring
1
$ = Corresponde ao final da string
PeterBechP
1
@JasonSebring Embora eu concorde que a validação de entrada não é uma má ideia, a melhor abordagem é um algoritmo de escape real. E as exceções nem mesmo são o pior problema, mas imagine que você usou um código semelhante em uma página de login e um usuário inserido ".*"como nome de usuário.
Tobias
79

Tive problemas com isso recentemente, uso esse código e funciona bem para mim.

var data = 'Peter';

db.User.find({'name' : new RegExp(data, 'i')}, function(err, docs){
    cb(docs);
});

Uso direto /Peter/itrabalho, mas uso '/'+data+'/i'e não trabalho para mim.

Donflopez
fonte
Bem, eu apenas tentei mais um pouco. Também vejo se eu apenas escrever P ?? hmmm.
PeterBechP
Sim, eu uso para petições ajax para pesquisar usuários. Você pode modificar o RegExp.
Donflopez
35
db.users.find( { 'username' : { '$regex' : req.body.keyWord, '$options' : 'i' } } )
Kanomdook
fonte
@MikeShi Qual é um exemplo de cenário disso?
Len Joseph
@LenJoseph, em geral, o ataque ReDoS: owasp.org/index.php/… , não sei se o mangusto está vulnerável neste ponto, ou se existe alguma funcionalidade pretendida para detectar entradas ReDoS e higienizá-los no nível do mangusto.
Mike Shi
14
collection.findOne({
    username: /peter/i
}, function (err, user) {
    assert(/peter/i.test(user.username))
})
Raynos
fonte
e se o valor for uma var? Como configurar isso? / varhere / i?
PeterBechP
2
@PeterBechP constrói uma expressão regular: \new RegExp(var, "i")
Raynos,
funciona bem .. agora estou com um problema .. Só preciso encontrar peter se var for peter. Mas se eu definir a var como 'p', ainda encontrará peter.
PeterBechP
@PeterBechP, em seguida, remova o sinalizador de insensibilidade a maiúsculas e minúsculas: \
Raynos,
14
router.route('/product/name/:name')
.get(function(req, res) {

    var regex = new RegExp(req.params.name, "i")
    ,   query = { description: regex };

    Product.find(query, function(err, products) {
        if (err) {
            res.json(err);
        }

        res.json(products);
    });

});  
victorkurauchi
fonte
13

Você deve usar um regex para isso.

db.users.find({name: /peter/i});

Porém, tenha cuidado, pois esta consulta não usa índice.

Sergio Tulentsev
fonte
9

mongoose doc para encontrar. mongodb doc para regex.

var Person = mongoose.model('Person', yourSchema);
// find each person with a name contains 'Ghost'
Person.findOne({ "name" : { $regex: /Ghost/, $options: 'i' } },
    function (err, person) {
             if (err) return handleError(err);
             console.log('%s %s is a %s.', person.name.first, person.name.last, person.occupation);
});

Observe o primeiro argumento que passamos para mongoose.findOnea função: { "name" : { $regex: /Ghost/, $options: 'i' } }, "name"é o campo do documento que você está procurando, "Ghost"é a expressão regular, "i"é a maiúsculas e minúsculas. Espero que isso ajude você.

Shashith Darshana
fonte
quais são as $ options
kabuto178
8

A consulta a seguir encontrará os documentos com maiúsculas e minúsculas necessárias de forma insensível e com ocorrência global também

var name = 'Peter';
    db.User.find({name:{
                         $regex: new RegExp(name, "ig")
                     }
                },function(err, doc) {
                                     //Your code here...
              });
pró-desenvolvedor
fonte
6

É isso que estou usando.

module.exports.getBookByName = function(name,callback){
    var query = {
            name: {$regex : name}
    }
    User.find(query,callback);
}
vikvincer
fonte
5

Aqui está meu código com expressJS:

router.route('/wordslike/:word')
    .get(function(request, response) {
            var word = request.params.word;       
            Word.find({'sentence' : new RegExp(word, 'i')}, function(err, words){
               if (err) {response.send(err);}
               response.json(words);
            });
         });
Enrico Giurin
fonte
1

se eu quiser consultar todos os registros em alguma condição, posso usar isso:

if (userId == 'admin')
  userId = {'$regex': '.*.*'};
User.where('status', 1).where('creator', userId);
independente
fonte
Parece um uso desnecessário de $regexquando você poderia apenas usar { $exists: true }.
sean
0

Complementando a resposta de @PeterBechP.

Não se esqueça de escapar dos caracteres especiais. https://stackoverflow.com/a/6969486

function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

var name = 'Peter+with+special+chars';

model.findOne({name: new RegExp('^'+escapeRegExp(name)+'$', "i")}, function(err, doc) {
  //Do your action here..
});
felipepastorelima
fonte
0

Esta é minha solução para converter todos os valores em req.body em um parâmetro LIKE de mangusto :

let superQ = {}

Object.entries({...req.body}).map((val, i, arr) => {
    superQ[val[0]] = { '$regex': val[1], '$options': 'i' }
})

User.find(superQ)
  .then(result => {
    res.send(result)})
  .catch(err => { 
    res.status(404).send({ msg: err }) })
Solomon Bush
fonte