Mongoose's find method with $or condition does not work properly

Mongodbnode.jsMongoose

Mongodb Problem Overview


Recently I start using MongoDB with Mongoose on Nodejs.

When I use Model.find method with $or condition and _id field, Mongoose does not work properly.

This does not work:

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

By the way, if I remove the '_id' part, this DOES work!

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

And in MongoDB shell, both work properly.

Mongodb Solutions


Solution 1 - Mongodb

I solved it through googling:

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);
});

Solution 2 - Mongodb

I implore everyone to use Mongoose's query builder language and promises instead of callbacks:

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

Read more about Mongoose Queries.

Solution 3 - Mongodb

You can also add a mix of $or and and to give your functions more flexibility, options and robustness, like so:

var ObjectId = require("mongoose").Types.ObjectId;
var idParam = new ObjectId(param.length < 12 ? "123456789012" : param);

const {nameParam, nicknameParam, ageParam} = req.params || req.body || req.query

User.find({
        $or: [{
                _id: objId
            },
            {
                name: nameParam
            },
            {
                nickname: nicknameParam
            }
        ],
        $and: [{
            age: ageParam
        }]
    },
    function (err, docs) {
        if (!err) res.send(docs);
    }
);

So this means that your find() will look for all users where (_id = idParam OR name = nameParam OR nickname = nicknameParam) AND (age = ageParam)

I hope this helps someone out there. Cheers!!!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionYounghanView Question on Stackoverflow
Solution 1 - MongodbYounghanView Answer on Stackoverflow
Solution 2 - MongodbGovind RaiView Answer on Stackoverflow
Solution 3 - MongodbAllJsView Answer on Stackoverflow