Quantum
Quantum

Reputation: 143

Query for search command with meteor and MongoDB

I'm building a meteor applications that stores problem messages in a DB. You can ask for a list with the messages but you can also search for messages. There are three search fields: Date, Patient ID and Request number. It's possible to search for messages with one or more of the fields. The respons are messages with all completed fields the same. Therefore I've built the following query:

Template.list.problems = function() {
 var d = Session.get('search_on_date');
 var p = Session.get('search_on_pid');
 var r = Session.get('search_on_req');

 var and_query = null;

 if (d!=null && p==null && r==null) and_query = {'Problem.DateTime': RegExp('^'+d)};
 if (d==null && p!=null && r==null) and_query = {'Problem.PID':p};
 if (d==null && p==null && r!=null) and_query = {'Problem.Request':r};
 if (d!=null && p!=null && r!=null) and_query = {$and: [{'Problem.DateTime': RegExp('^'+d)}, {'Problem.PID':p}, {'Problem.Request':r}]};
 if (d!=null && p!=null && r==null) and_query = {$and: [{'Problem.DateTime': RegExp('^'+d)}, {'Problem.PID':p}]};
 if (d==null && p!=null && r!=null) and_query = {$and: [{'Problem.PID':p}, {'Problem.Request':r}]};
 if (d!=null && p==null && r!=null) and_query = {$and: [{'Problem.DateTime': RegExp('^'+d)}, {'Problem.Request':r}]};

 return problems.find(and_query);
};

This solution works and I'm very happy about it. But my question is: is there a more efficient way to build the query? In this case I have to make an if-statement for each possible combination of completed fields. There are only three fields thus it's possible, but in case of many fields I suppose there must be a better solution.

So my question: how can I build a search query with AND condition in a very efficient way, without too many overhead?

Thanks.

Upvotes: 2

Views: 346

Answers (2)

Dave
Dave

Reputation: 2576

For your date, I'd give them a graphical datepicker and validate the input, then do an exact search with a javascript Date object, it'll be a lot faster than using a regex.

As for code cleanup I'd personally do something like this:

var $and = [];
if(d) $and.push({'Problem.DateTime': new RegExp('^' + d)});
if(p) $and.push({'Problem.PID':p});
if(r) $and.push({'Problem.Request':r});

if($and.length > 0) {
    if($and.length > 1) {
        return problems.find({ $and: $and });
    } else {
        return problems.find($and[0]);
    }
}

I realize coding style/readability its completely up to speculation, this is just how I'd do it.

Example query for the date:

var startDate = new Date(); // user supplied date
var endDate =  new Date(); // user supplied date again
endDate.setDate(endDate.getDate() + 1); // add a day
var query = { 
    'Problem.DateTime': { 
        $gte: startDate,
        $lt: endDate
    }
};

Upvotes: 0

Derick
Derick

Reputation: 36794

You could do something like this (psuedo code):

clauses = [];

if (d!=null) clauses.push( {'Problem.DateTime': RegExp('^'+d)} );
if (p!=null) clauses.push( {'Problem.PID':p} );
if (r!=null) clauses.push( {'Problem.Request':r} );

if (clauses.length == 1) {
    and_query = clauses[0];
} else {
    and_query = {$and: clauses};
}

return problems.find(and_query);

Upvotes: 1

Related Questions