Mongoose how to write a query with if condition?

aggregation-framework, mean-stack, mongodb, mongoose, node.js

Solution

You can use javascript to dynamically create json document based on your query parameters.

Your updated function will look something like

post.getSpecificDateRangeJobs = function(queryData, callback) {

  var matchCriteria = queryData.matchCriteria;
  var currentDate = new Date();

  // match document
  var match = {
    "expireDate": {
      "$gte": currentDate 
    }
  };

  if (matchCriteria !== "") {
    match["$text"]: {
      "$search": matchCriteria
    }
  };

  // group document
  var group = {
    _id: null
  };

  // Logic to calculate hours difference between current date and publish date is less than 30 hours.

  if (queryData.dateGroups.thirtyHourAgo) {
    group["thirtyHourAgo"] = {
      "$sum": {
        "$cond": [{
            "$lte": [{
              "$divide": [{
                "$subtract": [currentDate, "$publishDate"]
              }, 1000 * 60 * 60]
            }, 30]
          },
          1,
          0
        ]
      }
    };
  }

  // Similarly add more grouping condition based on query params.

  var postsCollection = post.getDataSource().connector.collection(
    post.modelName
  );

  // Use aggregate builder to create aggregation pipeline.

  postsCollection.aggregate()
    .match(match)
    .group(group)
    .exec(function(err, groupByRecords) {
      if (err) {
        return callback("err");
      }
      return callback(null, groupByRecords);
    });

};

Problem

Suppose I have the following query: ``` post.getSpecificDateRangeJobs = function(queryData, callback) { var matchCriteria = queryData.matchCriteria; var currentDate = new Date(); var match = { expireDate: { $gte: new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate()) } }; if (queryData.matchCriteria !== "") { match = { expireDate: { $gte: new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate()) }, $text: { $search: matchCriteria } }; } var pipeline = [ { $match: match }, { $group: { _id: null, thirtyHourAgo: { $sum: { $cond: [ { $gte: [ "$publishDate", new Date(queryData.dateGroups.thirtyHourAgo) ] }, 1, 0 ] } }, fourtyEightHourAgo: { $sum: { $cond: [ { $gte: [ "$publishDate", new Date(queryData.dateGroups.fourtyHourAgo) ] }, 1, 0 ] } }, thirtyDaysAgo: { $sum: { $cond: [ { $lte: [ "$publishDate", new Date(queryData.dateGroups.oneMonthAgo) ] }, 1, 0 ] } } } } ]; var postsCollection = post.getDataSource().connector.collection( post.modelName ); postsCollection.aggregate(pipeline, function(err, groupByRecords) { if (err) { return callback("err"); } return callback(null, groupByRecords); }); }; ``` What i want to do is: 1- check if `queryData.dateGroups.thirtyHourAgo` existed and has value, then only add the relevant match clause in query (count of posts only for past 30 hour). 2- check if `queryData.dateGroups.fourtyHourAgo` existed, then add relevant query section (count of posts for past 30 hour, and past 48 hour ago). 3 and the same for `queryData.dateGroups.oneMonthAgo` (count of posts for past 30 hour, 48 hour, and past one month). I need something like Mysql if condition to check if a variable existed and not empty then include a query clause. Is it possible to do that? My sample data is like: ``` /* 1 */ { "_id" : ObjectId("58d8bcf01caf4ebddb842855"), "vacancyNumber" : "123213", "position" : "dsfdasf", "number" : 3, "isPublished" : true, "publishDate" : ISODate("2017-03-11T00:00:00.000Z"), "expireDate" : ISODate("2017-05-10T00:00:00.000Z"), "keywords" : [ "dasfdsaf", "afdas", "fdasf", "dafd" ], "deleted" : false } /* 2 */ { "_id" : ObjectId("58e87ed516b51f33ded59eb3"), "vacancyNumber" : "213123", "position" : "Software Developer", "number" : 4, "isPublished" : true, "publishDate" : ISODate("2017-04-14T00:00:00.000Z"), "expireDate" : ISODate("2017-05-09T00:00:00.000Z"), "keywords" : [ "adfsadf", "dasfdsaf" ], "deleted" : false } /* 3 */ { "_id" : ObjectId("58eb5b01c21fbad780bc74b6"), "vacancyNumber" : "2432432", "position" : "Web Designer", "number" : 4, "isPublished" : true, "publishDate" : ISODate("2017-04-09T00:00:00.000Z"), "expireDate" : ISODate("2017-05-12T00:00:00.000Z"), "keywords" : [ "adsaf", "das", "fdafdas", "fdas" ], "deleted" : false } /* 4 */ { "_id" : ObjectId("590f04fbf97a5803636ec66b"), "vacancyNumber" : "4354", "position" : "Software Developer", "number" : 5, "isPublished" : true, "publishDate" : ISODate("2017-05-19T00:00:00.000Z"), "expireDate" : ISODate("2017-05-27T00:00:00.000Z"), "keywords" : [ "PHP", "MySql" ], "deleted" : false } ``` Suppose I have three link in my application interface: 1- 30 hour ago posts. 2- 48 hour ago posts. 3- last one month posts. Now if user click on first link i should control to group posts only for 30 hour ago, but if user click on second link, i should prepare my query to group posts for 30 hour and also for 48 hour, and if user click on third link i should prepare for all of them. I want something like: ``` var pipeline = [ { $match: match }, { $group: { _id: null, if (myVariable) { thirtyHourAgo: { ........ ........ } } if (mysecondVariable) { fortyEightHourAgo: { ........ ........ } } ```

Original source