tarek noaman
tarek noaman

Reputation: 1503

Match time only in mongodb aggregation

I am storing opening times as an array of shifts every day like below:

{
  Monday: [{
    startTime: {
      hour: 8, 
      minute: 50
    },
    endTime: {
      hour: 20, 
      minute: 30
    }
  }];
}

enter image description here

I am trying to retrieve documents between the start and end of a shift, using MongoDB aggregate $match operator like below:

{
  $match: {
    'Monday.startTime.hour': {              // ex: 8
      $lte: parseInt(now.format('HH'), 10), // now hours: 18
    },
    'Monday.startTime.minute': {            // ex: 50
      $lte: parseInt(now.format('mm'), 10), // now minutes: 40
    },
    'Monday.endTime.hour': {                // ex: 20
      $gte: parseInt(now.format('HH'), 10), // now hours: 18
    },
    'Monday.endTime.minute': {              // ex: 30
      $gte: parseInt(now.format('mm'), 10), // now minutes: 40
    },
  }
}

BUT the problem is that we have a shift example shown in the image below, the first match condition:

'Monday.startTime.hour': {
  $lte: parseInt(now.format('HH'), 10),
}

will pass as 8 is smaller than 18.

but the second match condition which matches the minutes part:

'Monday.startTime.minute': {            // ex: 50
  $lte: parseInt(now.format('mm'), 10), // now minutes: 40
},

will fail as 50 is greater than 40

although in real life 08:50 comes before 18:40

Upvotes: 3

Views: 653

Answers (2)

tarek noaman
tarek noaman

Reputation: 1503

I was able to solve the issue by comparing the hours first by using $and and $or operators see explained code below:

{
  $and: [ // grouping two conditions that now time needs to be between the start and the end of the shift.
    {
      $or: [ // compare the start time hour of the shift first 
        {
          'Monday.startTime.hour': {
            $lt: parseInt(now.format('HH'), 10),
          },
        },
        {
          $and: [ // if the upper condition didn't work will need to compare hours and minutes 
            {
              'Monday.startTime.hour': {
                $lte: parseInt(now.format('HH'), 10),
              },
            },
            {
              'Monday.startTime.minute': {
                $lte: parseInt(now.format('mm'), 10),
              },
            },
          ],
        },
      ],
    },
    {
      $or: [ // compare the end time hour of the shift first 
        {
          'Monday.endTime.hour': {
            $gt: parseInt(now.format('HH'), 10),
          },
        },
        {
          $and: [ // if the upper condition didn't work will need to compare hours and minutes
            {
              'Monday.endTime.hour': {
                $gte: parseInt(now.format('HH'), 10),
              },
            },
            {
              'Monday.endTime.minute': {
                $gte: parseInt(now.format('mm'), 10),
              },
            },
          ],
        },
      ],
    },
  ];
}

Upvotes: 1

Raghuraman Kesavan
Raghuraman Kesavan

Reputation: 71

Change Everything to Minutes. That will help you to solve this problem.

8:50 should be 530 and 20:30 should be 1230.

Current time will be 1120(18:40). So by changing to minutes you can able to solve this problem.

Upvotes: 0

Related Questions