> For the complete MongoDB documentation index, see www.mongodb.com/docs/llms.txt

<!--
Tab options on this page. Append to the .md URL to filter:
  ?tabs=<id,...>   select specific tabs (e.g. ?tabs=nodejs,shell)
  ?allTabs=true    include every tab
  (no param)       default: one tab per tabset

Available tabs:
  other tabs: ui, cli
-->

# Scheduled Triggers

Scheduled Triggers allow you to execute server-side logic on a [regular schedule that you define](https://www.mongodb.com/docs/atlas/atlas-ui/triggers/scheduled-triggers.md#std-label-atlas-CRON-expressions). You can use scheduled Triggers to do work that happens on a periodic basis, such as updating a document every minute, generating a nightly report, or sending an automated weekly email newsletter.

## Create a Scheduled Trigger

You can create a new scheduled Trigger from the Atlas UI or using the App Services CLI.

### Atlas UI

In Atlas, go to the Triggers page.

If it's not already displayed, select the organization that contains your project from the  Organizations menu in the navigation bar.

If it's not already displayed, select your project from the Projects menu in the navigation bar.

In the sidebar, click Triggers under the Streaming Data heading.

The [Triggers](https://cloud.mongodb.com/go?l=https%3A%2F%2Fcloud.mongodb.com%2Fv2%2F%3Cproject%3E%23%2Ftriggers) page displays.

Click Add Trigger to open the Trigger configuration page.

Select Scheduled Trigger type.

Configure the Trigger, then click Save.

## Configuration

Scheduled Triggers have the following configuration options:

| Field | Description |
| --- | --- |
| Trigger Type`type: <string>` | Select Scheduled. |
| Schedule Type`config.schedule: <string>` | Required. You can select Basic or Advanced. A Basic schedule executes the Trigger periodically based on the interval you set, such as "every five minutes" or "every Monday". An Advanced schedule runs the Trigger based on the custom [CRON expression](https://www.mongodb.com/docs/atlas/atlas-ui/triggers/scheduled-triggers.md#std-label-atlas-CRON-expressions) that you define. |
| Skip Events on Re-Enable`skip_catchup_event: <boolean>` | Disabled by default. If enabled, any change events that occurred while this Trigger was disabled will not be processed. |
| Event Type`function_name: <string>` | Within the Event Type section, you choose what action is taken when the Trigger fires. You can choose to run a [Function](https://www.mongodb.com/docs/atlas/atlas-ui/triggers/functions.md#std-label-atlas-functions) or use [AWS EventBridge.](https://www.mongodb.com/docs/atlas/atlas-ui/triggers/aws-eventbridge.md#std-label-atlas-aws-eventbridge) A Scheduled Trigger does not pass any arguments to its linked Function. |
| Trigger Name`name: <string>` | The name of the trigger. |

## CRON Expressions

CRON expressions are user-defined strings that use standard [cron](https://en.wikipedia.org/wiki/Cron) job syntax to define when a scheduled Trigger should execute. Atlas executes Trigger CRON expressions based on [UTC time](https://en.wikipedia.org/wiki/Coordinated_Universal_Time). Whenever all of the fields in a CRON expression match the current date and time, Atlas fires the Trigger associated with the expression.

## Expression Syntax

### Format

CRON expressions are strings composed of five space-delimited fields. Each field defines a granular portion of the schedule on which its associated Trigger executes:

```text
* * * * *
│ │ │ │ └── weekday...........[0 (SUN) - 6 (SAT)]
│ │ │ └──── month.............[1 (JAN) - 12 (DEC)]
│ │ └────── dayOfMonth........[1 - 31]
│ └──────── hour..............[0 - 23]
└────────── minute............[0 - 59]
```

| Field | Valid Values | Description |
| --- | --- | --- |
| `minute` | [0 - 59] | Represents one or more minutes within an hour. If the `minute` field of a CRON expression has a value of `10`, the field matches any time ten minutes after the hour (e.g. `9:10 AM`). |
| `hour` | [0 - 23] | Represents one or more hours within a day on a 24-hour clock. If the `hour` field of a CRON expression has a value of `15`, the field matches any time between `3:00 PM` and `3:59 PM`. |
| `dayOfMonth` | [1 - 31] | Represents one or more days within a month. If the `dayOfMonth` field of a CRON expression has a value of `3`, the field matches any time on the third day of the month. |
| `month` | `1  (JAN)`   `7  (JUL)``2  (FEB)`   `8  (AUG)``3  (MAR)`   `9  (SEP)``4  (APR)`   `10 (OCT)``5  (MAY)`   `11 (NOV)``6  (JUN)`   `12 (DEC)` | Represents one or more months within a year. A month can be represented by either a number (e.g. `2` for February) or a three-letter string (e.g. `APR` for April). If the `month` field of a CRON expression has a value of `9`, the field matches any time in the month of September. |
| `weekday` | `0 (SUN)``1 (MON)``2 (TUE)``3 (WED)``4 (THU)``5 (FRI)``6 (SAT)` | Represents one or more days within a week. A weekday can be represented by either a number (e.g. `2` for a Tuesday) or a three-letter string (e.g. `THU` for a Thursday). If the `weekday` field of a CRON expression has a value of `3`, the field matches any time on a Wednesday. |

### Field Values

Each field in a CRON expression can contain either a specific value or an expression that evaluates to a set of values. The following table describes valid field values and expressions:

| Expression Type | Description |
| --- | --- |
| **All Values**`(*)` | Matches all possible field values. Available in all expression fields. The following CRON expression schedules a Trigger to execute once every minute of every day: `* * * * *` |
| **Specific Value**`(<Value>)` | Matches a specific field value. For fields other than `weekday` and `month` this value will always be an integer. A `weekday` or `month` field can be either an integer or a three-letter string (e.g. `TUE` or `AUG`). Available in all expression fields. The following CRON expression schedules a Trigger to execute once every day at 11:00 AM UTC: `0 11 * * *` |
| **List of Values**`(<Expression1>,<Expression2>,...)` | Matches a list of two or more field expressions or specific values. Available in all expression fields. The following CRON expression schedules a Trigger to execute once every day in January, March, and July at 11:00 AM UTC: `0 11 * 1,3,7 *` |
| **Range of Values**`(<Start Value>-<End Value>)` | Matches a continuous range of field values between and including two specific field values. Available in all expression fields. The following CRON expression schedules a Trigger to execute once every day from January 1st through the end of April at 11:00 AM UTC: `0 11 * 1-4 *` |
| **Modular Time Step**`(<Field Expression>/<Step Value>)` | Matches any time where the step value evenly divides the field value with no remainder (i.e. when `Value % Step == 0`). Available in the `minute` and `hour` expression fields. The following CRON expression schedules a Trigger to execute on the 0th, 25th, and 50th minutes of every hour: `*/25 * * * *` |

## Example

An online store wants to generate a daily report of all sales from the previous day. They record all orders in the `store.orders` collection as documents that resemble the following:

```json
{
  _id: ObjectId("59cf1860a95168b8f685e378"),
  customerId: ObjectId("59cf17e1a95168b8f685e377"),
  orderDate: ISODate("2018-06-26T16:20:42.313Z"),
  shipDate: ISODate("2018-06-27T08:20:23.311Z"),
  orderContents: [
    { qty: 1, name: "Earl Grey Tea Bags - 100ct", price: Decimal128("10.99") }
  ],
  shippingLocation: [
    { location: "Memphis", time: ISODate("2018-06-27T18:22:33.243Z") },
  ]
}
```

### Atlas UI

| Field | Setting |
| --- | --- |
| Trigger Type | Scheduled |
| Schedule Type | Advanced |
| Set a CHRON schedule. | `07***` |

To generate the daily report, the store creates a scheduled Trigger that fires every day at `7:00 AM UTC`. When the Trigger fires, it calls its linked Atlas Function, `generateDailyReport`, which runs an aggregation query on the `store.orders` collection to generate the report. The Function then stores the result of the aggregation in the `store.reports` collection.

```javascript
exports = function() {
  // Instantiate MongoDB collection handles
  const mongodb = context.services.get("mongodb-atlas");
  const orders = mongodb.db("store").collection("orders");
  const reports = mongodb.db("store").collection("reports");

  // Generate the daily report
  return orders.aggregate([
    // Only report on orders placed since yesterday morning
    { $match: {
        orderDate: {
          $gte: makeYesterdayMorningDate(),
          $lt: makeThisMorningDate()
        }
    } },
    // Add a boolean field that indicates if the order has already shipped
    { $addFields: {
        orderHasShipped: {
          $cond: {
            if: "$shipDate", // if shipDate field exists
            then: 1,
            else: 0
          }
        }
    } },
    // Unwind individual items within each order
    { $unwind: {
        path: "$orderContents"
    } },
    // Calculate summary metrics for yesterday's orders
    { $group: {
        _id: "$orderDate",
        orderIds: { $addToSet: "$_id" },
        numSKUsOrdered: { $sum: 1 },
        numItemsOrdered: { $sum: "$orderContents.qty" },
        totalSales: { $sum: "$orderContents.price" },
        averageOrderSales: { $avg: "$orderContents.price" },
        numItemsShipped: { $sum: "$orderHasShipped" },
    } },
    // Add the total number of orders placed
    { $addFields: {
        numOrders: { $size: "$orderIds" }
    } }
  ]).next()
    .then(dailyReport => {
      reports.insertOne(dailyReport);
    })
    .catch(err => console.error("Failed to generate report:", err));
};

function makeThisMorningDate() {
  return setTimeToMorning(new Date());
}

function makeYesterdayMorningDate() {
  const thisMorning = makeThisMorningDate();
  const yesterdayMorning = new Date(thisMorning);
  yesterdayMorning.setDate(thisMorning.getDate() - 1);
  return yesterdayMorning;
}

function setTimeToMorning(date) {
  date.setHours(7);
  date.setMinutes(0);
  date.setSeconds(0);
  date.setMilliseconds(0);
  return date;
}
```

## Performance Optimization

Use the Query API with a [$match](https://www.mongodb.com/docs/manual/reference/operator/aggregation/match/) expression to reduce the number of documents your Function looks at. This helps your Function improve performance and not reach [Function memory limits.](https://www.mongodb.com/docs/atlas/atlas-ui/triggers/functions.md#std-label-atlas-function-constraints)

See also the [Example section for a Scheduled Trigger using a $match expression.](https://www.mongodb.com/docs/atlas/atlas-ui/triggers/scheduled-triggers.md#std-label-atlas-scheduled-trigger-example)
