How to write Mongoose Queries with optional express query-params?

11,912

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.

Share:
11,912
Ludwig Goohsen
Author by

Ludwig Goohsen

Updated on June 05, 2022

Comments

  • Ludwig Goohsen
    Ludwig Goohsen almost 2 years

    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);
            });
        });
    
  • Ludwig Goohsen
    Ludwig Goohsen almost 8 years
    ah cool, that's a start. But what if I don't test for equality, nor strings. So {$or: [{undefined: {$eq: qP.ageLower}}, {'age': {$gte: parseInt(qP.ageLower)}}]} wouldn't work like this, right? Also I'm having nestled fields I want to query. So the queryParameter city should actually test against address.city. Any ideas?
  • robertklep
    robertklep almost 8 years
    If you need more than simple equality checking you're going to have to process the incoming data anyway, or allow a more elaborate query format to be used (mongo-rql, monquery, mongo-querystring).