Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build a conditional query in Mongoose?

The following code works with no querystrings or one querystring only. In other words, simply going to /characters returns all characters. But if you were to specify a querystring parameter /characters?gender=male it will return only male characters.

How could I extend this to work with either 1, 2, 3, or no querystrings? I would really prefer to avoid writing 8 or 9 different if-statements for each case. I was hoping Mongoose would simply ignore a $where clause if it's null or undefined, but that is not the case (see commented out code).

  var gender = req.query.gender;
  var race = req.query.race;
  var bloodline = req.query.bloodline;

  var query = Character.find();

  if (gender)
    query = query.where('gender').equals(gender);
  if (race)
    query = query.where('race').equals(race);
  if (bloodline)
    query = query.where('bloodline').equals(bloodline);

  /*
  query
    .where('gender').equals(new RegExp('^' + gender + '$', 'i'))
    .where('race').equals(new RegExp('^' + race + '$', 'i'))
    .where('bloodline').equals(new RegExp('^' + bloodline + '$', 'i'));
  */

  query.exec(function(err, characters) {
    if (err) throw err;
    res.send(characters);
  });

Edit: Well I guess I could do it with 7 if-statements for now. Unless someone finds a more elegant solution.

Edit 2:

Thanks guys. It's difficult to pick one answer because both of you have helped me to achieve this concise solution. Here is the entire thing now.

var conditions = {};

for (var key in req.query) {
  if (req.query.hasOwnProperty(key)) {
    conditions[key] = new RegExp('^' + req.query[key] + '$', 'i');
  }
}

var query = Character.find(conditions);
query.exec(function(err, characters) {
  if (err) throw err;
  res.send({ characters: characters });
});
like image 568
Sahat Yalkabov Avatar asked Oct 30 '13 20:10

Sahat Yalkabov


People also ask

Can I use $in in Mongoose?

For example, if we want every document where the value of the name field is more than one value, then what? For such cases, mongoose provides the $in operator. In this article, we will discuss how to use $in operator. We will use the $in method on the kennel collection.

What is findById in Mongoose?

In MongoDB, all documents are unique because of the _id field or path that MongoDB uses to automatically create a new document. For this reason, finding a document is easy with Mongoose. To find a document using its _id field, we use the findById() function.

What does exec () do Mongoose?

In mongoose, exec method will execute the query and return a Promise.

What does REF do in Mongoose schema?

The ref option is what tells Mongoose which model to use during population, in our case the Story model. All _id s we store here must be document _id s from the Story model. Note: ObjectId , Number , String , and Buffer are valid for use as refs.


1 Answers

You don't need to call Query#where repeatedly, since you can pass all the conditions to Mongoose Model#find as:

var filteredQuery = {},
  acceptableFields = ['gender', 'race', /* etc */ ];

acceptableFields.forEach(function(field) {
  req.query[field] && filteredQuery[field] = req.query[field];
});

var query = Character.find(filteredQuery);

You'll also want to sanitize req.query depending on the allowed parameters you have in mind.

like image 95
rvidal Avatar answered Oct 06 '22 01:10

rvidal