Let us start with requirements

Business Requirements

The system needs to accept subcriptions from users with certain period time. After the paid subscription expires, the subscription status in user profile should be downgraded from a subscriped user to a normal user.

Make A Choice among Two Options

MongoDB TTL Index vs Node Schedule

As introduced in one of my previous writing regarding the System Architect , the system uses MongoDB to store user data. To add the function into the system, there were two choices that immediately came to my mind: MongoDB TTL Indexes and Node Schedule

  • Node Schedule
    Node schedule runs on the server side, for example, node-schedule. But since the requirement is to change user’s subscription status after certain amount of time (relatively long, like a week, a month etc.), and it will only run once, putting such burden on the server side for such task is not worth it.

  • MongoDB TTL Indexes
    Compare to Node Schedule, MongoDB TTL Indexes run on the database side, it will not create extra jobs on the server, it is a better choice for such requirement.

MongoDB TTL Indexes

Directly create MongoDB TTL Indexes

Clearly, in my case, I need to create MongoDB TTL Indexes with give parameters after the schema is generated. And after searching for a while, I realised that in mongoose, I can only create TTL indexes when create the schema, it is not possible to create TTL indexes with give parameters when the app is running (please correct me if I am wrong here). Within mongoose, it only can introduce TTL Index within schema definition, as shown below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import mongoose from 'mongoose';
const { Schema } = mongoose;

const XXXSchema = new Schema(
{
username: {
type: String,
required: true,
unique: true,
},
},
// timestamp of the creation data of the user
{ timestamps: true }
);

XXXSchema.index(
{ createdAt: 1 },
{
expireAfterSeconds: 30,
partialFilterExpression: { username: { $eq: 'xxx' } },
}
);

Indirectly create MongoDB TTL Indexes

Luckily, there is an alternative method to save my life: using expireAt in the schema. Under the table, the expireAt generates TTL indexes in MongoDB. Below are how I did it:

  1. introduce expireAt in the schema with expires property
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import mongoose from 'mongoose'
const { Schema } = mongoose

const XXXSchema = new Schema(
{
username: {
type: String,
required: true,
unique: true,
},
expireAt: {
type: Date,
default: Date.now,
expires: 0,
},
},
// timestamp of the creation data of the user
{ timestamps: true },
)
...
  1. when receiving the parameters, create the data with expireAt is set.
1
2
3
4
5
6
7
8
...
const newXXX = new XXX({
username: user.username,
expireAt: Date.now() + duration * 1000,
});

await newXXX.save();
...
  1. After the code in step 2 is ran, in the MongoDB, a TTL index should be seem. Let us take MongoDB Atlas as an example:
    Image

Job done :)

Comment and share

  • page 1 of 1
Author's picture

Jingjie Jiang


Find a place I love the most