# Realm Triggers Treats and Tricks - Document-Based Trigger Scheduling

In this blog series, we are trying to inspire you with some reactive Realm trigger use cases. We hope these will help you bring your application pipelines to the next level.

Essentially, triggers are components in our Atlas projects/Realm apps that allow a user to define a custom function to be invoked on a specific event.

-   **Database triggers:** We have triggers that can be scheduled based on database events—like `deletes`, `inserts`, `updates`, and `replaces`—called database triggers.
-   **Scheduled triggers:** We can schedule a trigger based on a `cron` expression via scheduled triggers.
-   **Authentication triggers:** These triggers are only relevant for Realm authentication. They are triggered by one of the Realm auth providers' authentication events and can be configured only via a Realm application.

For this blog post, I would like to focus on trigger scheduling patterns.

Let me present a use case and we will see how the discussed mechanics might help us in this scenario. Consider a meeting management application that schedules meetings and as part of its functionality needs to notify a user 10 minutes before the meeting.

How would we create a trigger that will be fired 10 minutes before a timestamp which is only known by the "meeting" document?

First, let's have a look at the meetings collection documents example:

``` javascript
{
  _id : ObjectId("5ca4bbcea2dd94ee58162aa7"),
  event : "Mooz Meeting",
  eventDate : ISODate("2021-03-20:14:00:00Z"),
  meetingUrl : "https://mooz.meeting.com/5ca4bbcea2dd94ee58162aa7",
  invites : "jon.doe@myemail.com", "doe.jonas@myemail.com"]
 }
```

I wanted to share an interesting solution based on triggers, and throughout this article, we will use a meeting notification example to explain the discussed approach.

## Prerequisites

First, verify that you have an Atlas project with owner privileges to create triggers.

-   [MongoDB Atlas account, Atlas cluster
-   A MongoDB Realm application or access to MongoDB Atlas triggers.

> If you haven't yet set up your free cluster on MongoDB Atlas, now is a great time to do so. You have all the instructions in this blog post.

## The Idea Behind the Main Mechanism

I will use the event example as a source document initiating the flow
with an insert to a `meetings` collection:

``` javascript
{
  _id : ObjectId("5ca4bbcea2dd94ee58162aa7"),
  event : "Mooz Meeting",
  eventDate : ISODate("2021-03-20:11:00:00Z"),
  meetingUrl : "https://mooz.meeting.com/5ca4bbcea2dd94ee58162aa7"
  invites : "jon.doe@example.com"],
  phone : "+123456789"
}
```

Once we insert this document into the `meetings` collection, it will create the following record in a helper collection called `notifications` using an insert trigger:

``` javascript
{
  _id : ObjectId("5ca4bbcea2dd94ee58162aa7"),
  triggerDate : ISODate("2021-03-10:50:00:00Z")
}
```

The time and `_id` are calculated from the source document and aim to fire once `2021-03-10:50:00:00Z` arrives via a `fireScheduleTasks` trigger. This trigger is based on a delete operation out of a [TTL index on the `triggerDate` field from the `notifications`.

This is when the user gets the reminder!

On a high level, here is the flow described above.

A meeting document is tracked by a trigger, creating a notification document. This document at the specified time will cause a delete event. The delete will fire a notification trigger to notify the user.

There are three main components that allow our system to trigger based on our document data.

## 1. Define a Notifications Helper Collection

First, we need to prepare our `notifications` collection. This collection will be created implicitly by the following index creation command.

Now we will create a TTL index. This index will cause the schedule document to expire when the value in `triggerDate` field arrives at its expiry lifetime of 0 seconds after its value.

``` javascript
db.notifications.createIndex( { "triggerDate": 1 }, { expireAfterSeconds: 0 } )
```

## 2. Building a Trigger to Populate the Schedule Collection

When setting up your `scheduleTasks` trigger, make sure you provide the following:

1.  Linked Atlas service and verify its name.
2.  The database and collection name we are basing the scheduling on, e.g., `meetings`.
3.  The relevant trigger operation that we want to schedule upon, e.g., when an event is inserted.
4.  Link it to a function that will perform the schedule collection population.

My trigger UI configuration to populate the scheduling collection.

To populate the `notifications` collection with relevant triggering dates, we need to monitor our documents in the source collection. In our case, the user's upcoming meeting data is stored in the "meeting" collection with the userId field. Our trigger will monitor inserts to populate a Scheduled document.

``` javascript
exports = function(changeEvent) {
  // Get the notifications collection
  const coll = context.services.get("").db("").collection("notifications");

  // Calculate the "triggerDate" and populate the trigger collection and duplicate the _id
  const calcTriggerDate = new Date(changeEvent.fullDocument.eventDate - 10 * 60000);   
  return coll.insertOne({_id:changeEvent.fullDocument._id,triggerDate: calcTriggerDate });
};
```

>Important: Please replace \ and \ with your linked service and database names.

## 3. Building the Trigger to Perform the Action on the "Trigger Date"

To react to the TTL "delete" event happening exactly when we want our scheduled task to be executed, we need to use an "on delete" database trigger I call `fireScheduleTasks`.

When setting up your `fireScheduleTasks` trigger, make sure you provide the following:

1.  Linked Atlas service and verify its name.
2.  The database and collection for the notifications collection, e.g., `notifications`.
3.  The relevant trigger operation that we want to schedule upon, which is "DELETE."
4.  Link it to a function that will perform the fired task.

Now that we have populated the `notifications` collection with the `triggerDate`, we know the TTL index will fire a "delete" event with the relevant deleted `_id` so we can act upon our task.

In my case, 10 minutes before the user's event starts, my document will reach its lifetime and I will send a text using Twilio service to the attendee's phone.

A prerequisite for this stage will be to set up a Twilio service using your Twilio cloud credentials.

1.  Make sure you have a Twilio cloud account with its SID and your Auth token.
2.  Set up the SID and Auth token into the Realm Twilio service configuration.
3.  Configure your Twilio Messaging service and phone number.

Once we have it in place, we can use it to send SMS notifications to our invites.

``` javascript
exports = async function(changeEvent) {
  // Get meetings collection
  const coll = context.services.get("").db("").collection("meetings");

  // Read specific meeting document
  const doc = await coll.findOne({ _id: changeEvent.documentKey._id});

  // Send notification via Twilio SMS
  const twilio = context.services.get("");
  twilio.send({
    to: doc.phone,
    from: "+123456789",
    body: `Reminder : Event ${doc.event} is about to start in 10min at ${doc.scheduledOn}`
    });
};
```

>Important: Replace \ and \ with your linked service and database names.

That's how the event was fired at the appropriate time.

## Wrap Up

With the presented technique, we can leverage existing triggering patterns to build new ones. This may open your mind to other ideas to design your next flows on MongoDB Realm.

In the following article in this series, we will learn how we can implement auto-increment with triggers.

> If you have questions, please head to our developer community website where the MongoDB engineers and the MongoDB community will help you build your next big idea with MongoDB.