Node.js – How to write Mongoose Queries with optional express query-params

expressmongodbmongoosenode.jsrest

I am building a REST API on top of Express 4. For a path lets say GET /api/users I want to query my users collection accordingly to optional queryParams.

So a call to the API could look like this host:port/api/users?city=Berlin

In this case name is omitted and doesn't influence the query, whereas city has to match.

I managed to do this with the following hack. Is there a better way than that?

Users.statics.customFilter = function(qP){
    return this.find({
        $and: [
            {$or: [{undefined: {$eq: qP.city}}, {'city': qP.city}]},
            {$or: [{undefined: {$eq: qP.name}}, {'name': qP.name}]}
        ]
    });

mongoose.model('User', Users);

I'm calling this static function from the mongoose schema like this…

const User = mongoose.model('User');
app.get('/api/users', (req, res) => {
        User.customFilter(req.query)
        .exec((err, results) => {
            if (err) return next(err);
            res.json(results);
        });
    });

Best Answer

It seems to me that in essence, User.find(req.query) should do what you want:

/api/users?city=Berlin           → User.find({ city : 'Berlin' })
/api/users?name=John             → User.find({ name : 'John' })
/api/users?name=John&city=Berlin → User.find({ city : 'Berlin', name : 'John' })

Of course, you have to decide what should happen if no parameters are passed (in the example above, it would become a query that would match all users, which may not be what you want).

Also, you should probably filter req.query so it only contains fields that are defined in your schema.