How to convert BSON Timestamp from Mongo changestream to a date?

Viewed 2145

I am getting started with the Changestream in Mongo. In my current setup a stitch functions inserts the changelog events into a revision collection. However when I read data from the collection, I can't convert the Timestamp fields. I have tried with the following 2 attempts:

1) A pipeline

[
    {
        $match: {
            'documentKey._id': _id,
        },
    },
    {
        $sort: { _id: -1 },
    },
    {
        $addFields: {
            convertedDate: { $toDate: 'clusterTime' },
        },
    },
]

But it gives the error: Error parsing date string 'clusterTime'; 0: passing a time zone identifier as part of the string is not allowed 'c'; 6: Double timezone specification 'r'

2) The bson Timestamp class

import { Timestamp } from 'bson';
const asTimestampInstance = new Timestamp(v.clusterTime);

But here typescript gives me the error: Expected 2 arguments, but got 1.ts(2554) index.d.ts(210, 30): An argument for 'high' was not provided.

In Altas, the clustertime correctly looks like a timestamp:

Screenshot of data in Atlas

I hope that I am just missing something simple :)

2 Answers

Unfortunately $toDate doesn't work with timestamps directly. At least not in v4.0.

The argument should be either a number, a string, or an ObjectId.

You need to convert Timestamp to string first:

    $addFields: {
        convertedDate: { $toDate: {$dateToString:{date:"$clusterTime"}} },
    },
2) The bson Timestamp class

You should take first 32-bit value from BSON's Timestamp class instance, it means seconds Epoch time, then multiply seconds on 1000 and make it milliseconds Epoch time, then call JS Date constructor.

If v is document from ChangeStream, v.clusterTime is BSON Timestamp class object. So, you should write:

const date = new Date(v.clusterTime.getHighBits() * 1000);

This example worked for me on MongoDB 4.0, ODM Mongoose 5.12, Node.js 12.

Related