1

I'm making an application with chats and posts, and in the chat, I want to show the time of the most recent post. The date part of my mongoose schema for posts is below, as well as a picture of what my Mongodb date field looks like.

I'm trying to get the date to the front end, but am unsure about how to format it. I want to format it as yesterday at 12:45pm or 6 days ago, etc. Any help is very much appreciated.

Mongoose Schema field for date:

     date: {
        type: Date,
        default: Date.now
      }

Mongodb data field

Tom Slabbaert
  • 21,288
  • 10
  • 30
  • 43
richard59897
  • 93
  • 1
  • 8
  • this answer could be helpful for you. [mongodb-nodejs-how-to-query-isodate-fields](https://stackoverflow.com/questions/20561381/mongodb-nodejs-how-to-query-isodate-fields) – Roshan Chauhan Aug 14 '20 at 08:07
  • Mongo will store it in a valid date format always, you have to get a converter involved to parse it that way to show it on UI. Because it will always be a relative problem, today is tomorrow's yesterday. – Abhishek Chauhan Aug 14 '20 at 08:36

1 Answers1

1

Mongo (and almost? no other database in the world) stores constants like "yesterday" or "last week".

The problem with these concepts like "yesterday" is that it's very semantic. if it's 00:01 is yesterday 2min ago? if the answer is yes you will actually have to update your database every minute if you're willing to compromise to look at time difference you will still have to do it every day.

I'm not sure what your actual business needs that make you want to do this. but I recommend you do it whilst fetching documents. otherwise this is not scaleable.

Here is a quick example on how to do this:

db.collection.aggregate([
  {
    "$addFields": {
      currDay: {
        "$dayOfMonth": "$$NOW"
      },
      dateDay: {
        "$dayOfMonth": "$date"
      },
      dayGap: {
        "$divide": [
          {
            "$subtract": [
              "$$NOW",
              "$date"
            ]
          },
          86400000/**miliseconds in a day*/
          
        ]
      }
    }
  },
  {
    $addFields: {
      date: {
        "$switch": {
          "branches": [
            {
              "case": {
                $and: [
                  {
                    $lt: [
                      "$dayGap",
                      1
                    ]
                  },
                  {
                    $eq: [
                      "$dateDay",
                      "$currDay"
                    ]
                  }
                ]
              },
              "then": "today"
            },
            {
              "case": {
                $lt: [
                  "$dayGap",
                  2
                ]
              },
              "then": "yesterday"
            },
            {
              "case": {
                $lt: [
                  "$dayGap",
                  1
                ]
              },
              "then": "today"
            }
          ],
          default: {
            "$concat": [
              {
                "$toString": {
                  "$round": "$dayGap"
                }
              },
              " days ago"
            ]
          }
        }
      }
    }
  }
],
{
  allowDiskUse: true
})

MongoPlayground

As you can see you'll have to manually construct the "phrase" you want for every single option. You can obviously do the same in code I just choose to show the "Mongoi" way as I feel is more complicated.

If you do end up choosing updating your database ahead of time you can use the same pipeline combined with $out to achieve this.

One final note is that I cheated a little as this aggregation looks at the miliseconds difference only (apart from today field). meaning if it's 1AM then 50 hours ago. even though the date is "three" days ago will still show up as two days ago.

I hope this example shows you why this formatting is not used anywhere and the difficulties it brings. Mind you I haven't even brought up timezones concepts like "yesterday" are even more semantic for different regions.

In my option the only viable "real" solution is to build a custom function that does this in code. mind you this is not so much fun as you have to account for events like gap years, timezones, geographical zone and more, however it is doable.

Tom Slabbaert
  • 21,288
  • 10
  • 30
  • 43