Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose - query $or slug / id

Tags:

mongoose

I'm trying to create a mongoose query that can query either by slug or id, however the problem comes in that I don't know which one I'm going to be handling as I have this as an Express route:

app.get('/animals/dogs/:id', function (req, res, next) {
     Dogs.find({$or: [{slug: id}, {_id: id}]}, function (err, docs) {
         if (err) {
             return next(err);
         }
         // ....
     });
});

I'd like to have ability to search by either, however this approach above throws up an Invalid ObjectId error.

Another approach would be to nest the queries, however this feels a bit cumbersome:

app.get('/animals/dogs/:id', function (req, res, next) {
     Dogs.find({slug: id}, function (err, docs) {
         if (err) {
             return next(err);
         }
         if (!docs) {
             Dogs.findById(id, function (err, docs) {
             // ...
             });
         }
         // ....
     });
});

Is there a any other approach I have not considered? I know I could turn my slug into the ObjectId, but I'd rather avoid this if possible.

like image 842
leepowell Avatar asked Dec 11 '12 17:12

leepowell


2 Answers

Test if id is a valid ObjectId and then only include that term in the query if it's valid:

app.get('/animals/dogs/:id', function (req, res, next) {
    var query = {$or: [{slug: id}]};
    if (id.match(/^[0-9a-fA-F]{24}$/)) {
        query.$or.push({_id: id});
    }
    Dogs.find(query, function (err, docs) {
        if (err) {
            return next(err);
        }
        // ....
    });
});
like image 50
JohnnyHK Avatar answered Jan 04 '23 06:01

JohnnyHK


I definitely prefer the following syntax (the use of Mongoose validator for ObjectId):

const mongoose   = require('mongoose');
const isObjectId = mongoose.ObjectId.isValid;

app.get('/animals/dogs/:id', function (req, res, next) {
  const id = req.params.id;
  const promise = isObjectId(id) ? Dogs.find(id) : Dogs.findOne({ slug: id });

  promise.then(dog => res.send(dog)).catch(next)
});
like image 22
merlin Avatar answered Jan 04 '23 06:01

merlin