O método find do Mongoose com $ ou condição não funciona corretamente

116

Recentemente, comecei a usar o MongoDB com o Mongoose no Nodejs.

Quando eu uso o método Model.find com $orcondição e _idcampo, o Mongoose não funciona corretamente.

Isso não funciona:

User.find({
  $or: [
    { '_id': param },
    { 'name': param },
    { 'nickname': param }
  ]
}, function(err, docs) {
   if(!err) res.send(docs);
});

A propósito, se eu remover a parte '_id', isso FUNCIONA!

User.find({
  $or: [
    { 'name': param },
    { 'nickname': param }
  ]
}, function(err, docs) {
   if(!err) res.send(docs);
});

E no shell do MongoDB, ambos funcionam corretamente.

Younghan
fonte

Respostas:

211

Resolvi isso pesquisando no Google:

var ObjectId = require('mongoose').Types.ObjectId;
var objId = new ObjectId( (param.length < 12) ? "123456789012" : param );
// You should make string 'param' as ObjectId type. To avoid exception, 
// the 'param' must consist of more than 12 characters.

User.find( { $or:[ {'_id':objId}, {'name':param}, {'nickname':param} ]}, 
  function(err,docs){
    if(!err) res.send(docs);
});
Younghan
fonte
2
você pode descrever por que essa solução funciona com palavras? obrigado
Alexander Mills
Isso parece uma solução para um problema bastante específico. Você pode ter que continuar procurando.
Kesarion de
Você poderia fornecer sua referência? Por que, neste caso, o parâmetro deve ter mais de 12 caracteres? Isso é específico ao seu problema ou ao requisito de ObjectId ()? E se meu param não tiver 12 caracteres? Obrigado!
yusong
6
você também pode verificar ObjectId da seguinte forma:const mongoose = require('mongoose'); mongoose.Types.ObjectId.isValid(objectidtocheck)
Orhan
@yusong é devido ao mongoose que lançará um erro se não for um ObjectId válido. Uma maneira mais limpa de fazer isso mencionada acima.
Haydar Ali Ismail
53

Imploro a todos que usem a linguagem de construção de consultas e promessas do Mongoose em vez de callbacks:

User.find().or([{ name: param }, { nickname: param }])
    .then(users => { /*logic here*/ })
    .catch(error => { /*error logic here*/ })

Leia mais sobre as consultas do Mongoose .

Govind Rai
fonte
Adoro! Obrigado pelo aviso!
zeckdude
0

De acordo com a documentação do mongoDB: "... Ou seja, para o MongoDB usar índices para avaliar um $ ou expressão, todas as cláusulas em $ ou expressão devem ser suportadas por índices."

Portanto, adicione índices para seus outros campos e isso funcionará. Eu tive um problema semelhante e isso resolveu.

Você pode ler mais aqui: https://docs.mongodb.com/manual/reference/operator/query/or/

Farasi78
fonte
1
esta é uma declaração errada - você só precisa de índices SE precisar que eles sejam usados ​​- ou seja, para desempenho, para evitar uma varredura de coleção. Mas se o desempenho não for um problema (por exemplo, a coleção é muito pequena), então não importa.
Andy Lorenz
0
async() => {
let body = await model.find().or([
  { name: 'something'},
  { nickname: 'somethang'}
]).exec();
console.log(body);
}
/* Gives an array of the searched query!
returns [] if not found */
Firez
fonte
1
Qual a diferença entre a sua resposta e a de Govind Rai? O que torna o seu superior ao deles?
BDL
async / await, nada o torna superior?
Firez
2
Respostas apenas em código são geralmente desaprovadas neste site. Você poderia editar sua resposta para incluir alguns comentários ou explicações sobre seu código? As explicações devem responder a perguntas como: O que isso faz? Como isso faz? Onde isso vai? Como isso resolve o problema do OP? Veja: Como responder . Obrigado!
Eduardo Baitello