Auto Delete Expired Documents in MongoDB with Node.js (TTL Index)

mail
Cyrus Kao
Last modified

TTL Indexes in MongoDB are very useful for storing data like logs or user sessions. The documents will remove itself after certain amount of time which specify by the index. This tutorial will be done in both JavaScript and TypeScript using Node.js with node-mongodb-native, which is the official MongoDB Node.js driver.

Install MongoDB Node.js Driver

Install node-mongodb-native from NPM if you haven't:

npm i mongodb
Bash

Connect to MongoDB

Connect to MongoDB and select the database of your choice:

  • JavaScript

    const MongoClient = require('mongodb').MongoClient;
    
    async function init() {
    	const Client = await MongoClient.connect('mongodb://127.0.0.1:27017'); // change it to the address your MongoDB is listening on
    	const Database = Client.db('MyDatabase'); // change it to the database name of your choice
    }
    JavaScript
  • TypeScript

    import { MongoClient } from 'mongodb';
    
    async function init() {
    	const Client = await MongoClient.connect('mongodb://127.0.0.1:27017'); // change it to the address your MongoDB is listening on
    	const Database = Client.db('MyDatabase'); // change it to the database name of your choice
    }
    TypeScript

Make sure MongoDB is up and running in the background.

Create/Select Collection

Select a collection, it'll create itself if it's not exist:

  • JavaScript

    ...
    async function init() {
    	...
    	const Collection = Database.collection('MyCollection'); // change it to the collection name of your choice
    }
    JavaScript
  • TypeScript

    ...
    interface Collection_MyCollection {
    	date: Date;
    	msg: string;
    } // create a interface specifying the type of the document
    
    async function init() {
    	...
    	const Collection = Database.collection<Collection_MyCollection>('MyCollection'); // change it to the collection name of your choice
    }
    TypeScript

Create TTL (Time-To-Live) Index

Create the TTL index on the collection:

...
async function init() {
	...
	await Collection.createIndex({
		date: 1, // 1 for ascending, -1 for descending
	}, {
		expireAfterSeconds: 60 * 60 * 24, // expire after 24 hours
	}); // documents will expire after 24 hours relative to the field `date`
}
JavaScript

The field you specify should be in type Date, otherwise the documents won't expire.

Try It Out

We'll create a function called printDocuments to print out the documents in the collection, and insert two documents with the current date and day before to see if it expires correctly:

...
async function init() {
	...
	async function printDocuments() {
		console.log(await Collection.find({}).toArray()); // print all documents in the collection
	}

	await Collection.insertOne({
		date: new Date(), // today
		msg: 'this won\'t expire soon',
	});

	await Collection.insertOne({
		date: new Date(Date.now() - 60 * 60 * 24 * 1000), // yesterday
		msg: 'this will expire soon',
	});

	printDocuments();

	setTimeout(() => {
		printDocuments();
	}, 60 * 2 * 1000); // since MongoDB only performs deletion every 60 seconds, we'll check the documents after 2 minutes
}

init(); // execute the function
JavaScript
[
	{
		_id: new ObjectId("6203411f91c0d03dffa77509"),
		date: 2022-02-09T04:20:47.313Z,
		msg: "this won't expire soon"
	},
	{
		_id: new ObjectId("6203411f91c0d03dffa7750a"),
		date: 2022-02-08T04:20:47.317Z,
		msg: 'this will expire soon'
	}
]
Output
[
	{
		_id: new ObjectId("6203411f91c0d03dffa77509"),
		date: 2022-02-09T04:20:47.313Z,
		msg: "this won't expire soon"
	}
]
Output

Be aware that MongoDB runs the background task that removes expired documents every 60 seconds, so there will be a short period of delay before the expired documents got deleted.

Official documentation
Official documentation of MongoDB

If the document didn't got deleted, verify the index is created correctly:

Indexes
Indexes on MongoDB Compass

Full Example

A full example including above steps:

  • JavaScript

    const MongoClient = require('mongodb').MongoClient;
    
    async function init() {
    	const Client = await MongoClient.connect('mongodb://127.0.0.1:27017');
    	const Database = Client.db('MyDatabase');
    	const Collection = Database.collection('MyCollection');
    
    	await Collection.createIndex({
    		date: 1,
    	}, {
    		expireAfterSeconds: 60 * 60 * 24,
    	});
    
    	async function printDocuments() {
    		console.log(await Collection.find({}).toArray());
    	}
    
    	await Collection.insertOne({
    		date: new Date(),
    		msg: 'this won\'t expire soon',
    	});
    
    	await Collection.insertOne({
    		date: new Date(Date.now() - 60 * 60 * 24 * 1000),
    		msg: 'this will expire soon',
    	});
    
    	printDocuments();
    
    	setTimeout(() => {
    		printDocuments();
    	}, 60 * 2 * 1000);
    }
    
    init();
    JavaScript
  • TypeScript

    import { MongoClient } from 'mongodb';
    
    interface Collection_MyCollection {
    	date: Date;
    	msg: string;
    }
    
    async function init() {
    	const Client = await MongoClient.connect('mongodb://127.0.0.1:27017');
    	const Database = Client.db('MyDatabase');
    	const Collection = Database.collection<Collection_MyCollection>('MyCollection');
    
    	await Collection.createIndex({
    		date: 1,
    	}, {
    		expireAfterSeconds: 60 * 60 * 24,
    	});
    
    	async function printDocuments() {
    		console.log(await Collection.find({}).toArray());
    	}
    
    	await Collection.insertOne({
    		date: new Date(),
    		msg: 'this won\'t expire soon',
    	});
    
    	await Collection.insertOne({
    		date: new Date(Date.now() - 60 * 60 * 24 * 1000),
    		msg: 'this will expire soon',
    	});
    
    	printDocuments();
    
    	setTimeout(() => {
    		printDocuments();
    	}, 60 * 2 * 1000);
    }
    
    init();
    TypeScript

Comments

0500