ivan
ivan

Reputation: 15

ignore a parameter in a query if it arrives null in Mongodb

I am trying to filter an array of publications in a project with angular node and mongo, but when doing the query in mongo I can't make it work.

Any way so that if the params.category parameter arrives null that parameter is not taken into account and the query works with the other parameters normally? I wanted to add two if before the query to make it work, but since I'm going to add another 3 filters (in addition to params.category) I would have to add a lot of if and it wouldn't look very good.

Hope someone can help me. ty

function getPublicationMap(req, res){
  var params = req.body;

  Publication.find({ $and: [{latitude: {$gt: params.south}}, {latitude: {$lt: params.north}}, {longitude: {$gt: params.west}}, 
   {longitude: {$lt: params.east}}, {category: {$eq: params.category}} ]}, (err, publications) =>{

    if(err) return res.status(500).send({message: 'Error'});
    if(!publications) return res.status(404).send({message: 'No publications'});
      return res.status(200).send({publications});
            });

    }


Upvotes: 0

Views: 3362

Answers (3)

Shivam Shrivastava
Shivam Shrivastava

Reputation: 1

It is quite simple

if (role.length > 0) { console.log(role);

            filterparams.push({ role: role });
        }
        if (min_salary > 0) {
            console.log(typeof min_salary);

            filterparams.push({ min_salary: { $gte: min_salary } });
        }
        if (max_salary > 0) {
            console.log(typeof max_salary);

            filterparams.push({ max_salary: { $lte: max_salary } });
        }
        if (job_type.length > 0) {
            filterparams.push({ job_type: job_type });
        }
        if (work_policy.length > 0) {
            console.log(work_policy);

            filterparams.push({ work_policy: work_policy });
        }

        if (search.length > 0) {
            console.log(`in search if condition`);

            filterparams.push({
                $text: {
                    $search: search
                }
            });
        }
        if (language.length > 0) {
            if (language.length > 1) {
                for (let i = 0; i < language.length; i++) langaugeparams.push({ 'job_desc.lang_code': language[i] });
                filterparams.push({ $or: langaugeparams });
            } else {
                filterparams.push({ 'job_desc.lang_code': language[0] });
            }
        }

var result = await LiveJobsDBModel.find({ $and: filterparams })

what I have done , is that I have made an Object , and checked each parameter manually. If it's value is present then only I am adding this into the filterparams array, well this worked for me .

the filterparams array would look something like this.

filterparams = :[{‘role’:role},{min_salary:{$gte:min_salary)}},{max_salary:{$lte:max_salary}},{‘job_type’:job_type},{‘work_policy’:work_policy}]

Upvotes: 0

LazyCat01
LazyCat01

Reputation: 1049

If you don't want to put bunch of IFs for some reason then "query factory" function can be created:

function maybeCreateMongoQuery(prop,queryProp,value){
  return value === null ? null : {[prop]: {[queryProp]: value}};
}

And then at middleware itself:

// ....
Publication.find({ $and: [
  maybeCreateMongoQuery('latitude', '$gt', params.south),
  maybeCreateMongoQuery('latitude', '$lt', params.north),
  // ...
  ].filter(q => q !== null)
}, (err, publications) => {
// ....
});

Also, .filter(q => q !== null) part can be extracted into separate function as well in case if you need to reuse solution multiple times.

But, keep in mind that by using such approach you're avoiding repetitive IFs on one hand, but increasing complexity on other hand. So, there are always tradeoffs.

Upvotes: 4

prasad_
prasad_

Reputation: 14317

The solution using aggregation:

db.collection.aggregate( [
  { 
    $addFields: { isParamCategoryNull: { $eq: [ params.category, null ] } } 
  },
  { 
    $addFields: { 
         matches: { 
             $cond: {
                  if: { $eq: [ "$isParamCategoryNull", true ] }, 
                  then: { $and: [ { $gt: [ "$latitude", param.south ] }, { $lt: [ "$latitude", param.north ] }, 
                                  { $gt: [ "$longitude", param.west ] }, { $lt: [ "$longitude", param.east ] } 
                                ] 
                         },
                  else: { $and: [ { $gt: [ "$latitude", param.south ] }, { $lt: [ "$latitude", param.north ] }, 
                                  { $gt: [ "$longitude", param.west ] }, { $lt: [ "$longitude", param.east ] }, 
                                  { $eq: [ "$category", param.category ] }
                                ] 
                         }
             }
     } }
  },
  { 
    $match: { matches: true }
  },
  { 
    $project: { matches: 0,  isParamCategoryNull: 0 } 
  }
] )

With these two input documents,

{ "_id" : 1, "latitude" : 12, "longitude" : 15, "category" : "xyz" },
{ "_id" : 2, "latitude" : 12, "longitude" : 18, "category" : "abc" }

when params = { south: 11, north: 15, west: 10, east: 20, category: null }, both documents will be selected. If the params.category = "xyz", then only the document with _id: 1 will be selected.

Upvotes: 0

Related Questions