7

I'm trying to build a MongoDB query object based on data received from a client-side search form. My goal is to query the database with any and all criteria provided by the user, whilst allowing the user to leave some search fields blank if they choose to.

This is my current attempt at a query object is:

var q = {}; // declare the query object
  q['$and']=[]; // filter the search by any criteria given by the user
  if((req.body.learninglanguages).length > 0){ // if the criteria has a value or values
    q["$and"].push('{learningLanguages: {$in: ' + req.body.learninglanguages.split(",") + '}}'); // add to the query object
  }
  if((req.body.spokenlanguages).length > 0){
    q["$and"].push('{spokenLanguages: {$in: ' + req.body.spokenlanguages.split(",") + '}}');
  }
  if((req.body.country).length > 0){
    q["$and"].push('{country: {$in: ' + req.body.country.split(",") + '}}');
  }
  if((req.body.commethod).length > 0){
    q["$and"].push('{comMethod: {$in: ' + req.body.commethod.split(",") + '}}');
  }

But the resulting object is:

{ '$and': 
   [ '{learningLanguages: {$in: Albanian,American Sign Language,Amharic,Arabic,Arabic (Egyptian)}}',
     '{spokenLanguages: {$in: Akan,Albanian,American Sign Language,Amharic}}',
     '{country: {$in: Åland Islands}}',
     '{comMethod: {$in: whatsapp,email,face to face,skype}}' ] }

How can I correctly build a MongoDB $in query from req.body objects?

5
  • Have you consulted the documentation? docs.mongodb.com/manual/reference/operator/query/in Commented Oct 11, 2016 at 21:05
  • I have, but I can't find anything helpful about building query objects dynamically. Commented Oct 11, 2016 at 21:14
  • Please be sure to check my answer below and mark it correct if it meets your needs Commented Oct 11, 2016 at 21:40
  • 1
    It exceeds my needs! Thanks for such a full and complete answer. Commented Oct 11, 2016 at 21:53
  • No problem! Glad I could help! Commented Oct 11, 2016 at 21:53

2 Answers 2

14

The problem with your query is you are attempting to build a string instead of directly building an object, like mongoDB & mongoose accept:

var q = {}; // declare the query object
  q['$and']=[]; // filter the search by any criteria given by the user
  if((req.body.learninglanguages).length > 0){ // if the criteria has a value or values
    q["$and"].push({ learningLanguages: {$in: req.body.learninglanguages.split(",") }}); // add to the query object
  }
  if((req.body.spokenlanguages).length > 0){
    q["$and"].push({ spokenLanguages: {$in: req.body.spokenlanguages.split(",") }});
  }
  if((req.body.country).length > 0){
    q["$and"].push({ country: {$in: req.body.country.split(",") }});
  }
  if((req.body.commethod).length > 0){
    q["$and"].push({ comMethod: {$in: req.body.commethod.split(",") }});
  }

You can see that instead of pushing in a string, I am instead pushing in a direct object that fits the documentation specifications.

See the documentation here for more information:

  1. https://docs.mongodb.com/manual/reference/operator/query/and/
  2. https://docs.mongodb.com/manual/reference/operator/query/in/

And here's a working jsbin you can play with:

  1. http://jsbin.com/cequbipiso/edit?js,console
Sign up to request clarification or add additional context in comments.

Comments

7

I followed Derek's suggestion, which is spot on in terms of how to dynamically construct the query conditions. But it appears that this code does not handle a scenario where no search parameters are specified.

Specifically, if all req.body parameters are empty, then you have a query object with an empty $and array as declared here:

q['$and']=[];

This results in a MongoError: $and/$or/$nor must be a nonempty array error.

Here's what I did to fix this issue:

var conditions = {}; //declare a conditions object
var and_clauses = []; //an array for the and conditions (and one for or conditions and so on)

if((!!req.body.email_id)){
    and_clauses.push({ 'email_id': {$regex: req.body.email_id }});
}   

if(and_clauses.length > 0){ 
    conditions['$and'] = and_clauses; // filter the search by any criteria given by the user
}

//Run the query
User.find(conditions,
    function(err, users) {
        if (err){
            console.log(err);
            res.status(500).send(err);
        }else{
            console.log(users);
            res.status(200).json(users);
        }
});

Derek, apologies if I got something wrong, don't want to point out an issue incorrectly.

2 Comments

Hi Vikas, thanks for adding the extra step to Derek answer. This worked well for my scenario.
Combining with Derek's logic, this solved my problem. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.