Docs Menu

Docs HomeAtlas App Services

Database Triggers

On this page

Database Triggers allow you to execute server-side logic whenever a document is added, updated, or removed in a linked MongoDB Atlas cluster. Unlike SQL data triggers, which run on the database server, triggers run on a serverless compute layer that scales independently of the database server. Triggers automatically call Atlas Functions and can forward events to external handlers through AWS EventBridge.

Use database triggers to implement event-driven data interactions. For example, you can automatically update information in one document when a related document changes or send a request to an external service whenever a new document is inserted.

Database triggers use MongoDB change streams to watch for real-time changes in a collection. A change stream is a series of database events that each describe an operation on a document in the collection. Your app opens a single change stream for each collection with at least one enabled trigger. If multiple triggers are enabled for a collection they all share the same change stream.

You control which operations cause a trigger to fire as well as what happens when it does. For example, you can run a function whenever a specific field of a document is updated. The function can access the entire change event, so you always know what changed. You can also pass the change event to AWS EventBridge to handle the event outside of Atlas.

Triggers support $match expressions to filter change events and $project expressions to limit the data included in each event.

Important

Change Stream Limitations

There are limits on the total number of change streams you can open on a cluster, depending on the cluster's size. See change stream limitations for more information.

You cannot define a database trigger on a serverless instance or Federated database instance because they do not support change streams.

Database Triggers have the following configuration options:

Field
Description
Trigger Type
Required. The type of the Trigger. Set this value to DATABASE for database Triggers
Trigger Name
Required. The name of the Trigger.
Linked Function
Required. The name of the Atlas Function that the Trigger executes whenever it fires. The Trigger passes the database event object that caused it to fire as the only argument to this Function.
Cluster
Required. The name of the MongoDB Service that the Trigger is associated with.
Database Name
Required. The MongoDB database that contains the watched collection.
Collection Name
Required. The name of the collection that the Trigger watches for change events.
Operation Types

Required. A list of one or more database operation types that cause the Trigger to fire. Format each operation type as an uppercase string, e.g., "INSERT".

Warning

Update operations executed from MongoDB Compass or the MongoDB Atlas Data Explorer fully replace the previous document. As a result, update operations from these clients will generate REPLACE change events rather than UPDATE events.

Full Document

If enabled, UPDATE change events include the latest majority-committed version of the modified document after the change was applied in the fullDocument field.

Note

Regardless of this setting:

  • INSERT and REPLACE events always include the fullDocument field.

  • DELETE events never include the fullDocument field.

Document Preimage

If enabled, change events include a copy of the modified document from immediately before the change was applied in the fullDocumentBeforeChange field. All change events except for INSERT events include the document preimage.

Tip

Performance Optimization

Disable preimages at a collection level to improve performance. Learn more.

Event Ordering

If event ordering is enabled, multiple executions of this Trigger will occur sequentially based on the timestamps of the change events. If event ordering is disabled, multiple executions of this Trigger will occur independently.

Tip

Performance Optimization

Improve performance for Triggers that respond to bulk database operations by disabling event ordering. Learn more.

Match Expression

Optional.

A $match expression document that App Services uses to filter which change events cause the Trigger to fire. The Trigger evaluates all change event objects that it receives against this match expression and only executes if the expression evaluates to true for a given change event.

Note

Use Dot-Notation for Embedded Fields

MongoDB performs a full equality match for embedded documents in a match expression. If you want to match a specific field in an embedded document, refer to the field directly using dot-notation. For more information, see Query on Embedded Documents in the MongoDB server manual.

Tip

Performance Optimization

Limit the number of fields that the Trigger processes by using a $match expression. Learn more.

Project Expression

Optional.

A $project expression that selects a subset of fields from each event in the change stream. You can use this to optimize the trigger's execution.

The expression is an object that maps the name of fields in the change event to either a 0, which excludes the field, or a 1, which includes it. An expression can have values of either 0 or 1 but not both together. This splits projections into two categories, inclusive and exclusive:

  • An inclusive project expression specifies fields to include in each change event document. The expression is an object that maps the name of fields to include to a 1. If you don't include a field, it is not included in the projected change event.

    Example

    The following projection includes only the _id and fullDocument fields:

    {
    _id: 1,
    fullDocument: 1
    }
  • An exclusive project expression specifies fields to exclude from each change event document. The expression is an object that maps the name of fields to include to a 0. If you don't exclude a field, it is included in the projected change event.

    Example

    The following projection excludes the _id and fullDocument fields:

    {
    _id: 0,
    fullDocument: 0
    }

    Note

    You cannot exclude the operation_type field with a projection. This ensures that the trigger can always check if it should run for a given event's operation type.

Auto-Resume Triggers

Optional.

If enabled, when this Trigger's resume token cannot be found in the cluster's oplog, the Trigger automatically resumes processing events at the next relevant change stream event. All change stream events from when the Trigger was suspended until the Trigger resumes execution do not have the Trigger fire for them.

Database change events represent individual changes in a specific collection of your linked MongoDB Atlas cluster.

Every database event has the same operation type and structure as the change event object that was emitted by the underlying change stream. Change events have the following operation types:

Operation Type
Description
INSERT
Represents a new document added to the collection.
UPDATE
Represents a change to an existing document in the collection.
REPLACE
Represents a new document that replaced a document in the collection.
DELETE
Represents a document deleted from the collection.

Database change event objects have the following general form:

{
_id : <ObjectId>,
"operationType": <string>,
"fullDocument": <document>,
"fullDocumentBeforeChange": <document>,
"ns": {
"db" : <string>,
"coll" : <string>
},
"documentKey": {
"_id": <ObjectId>
},
"updateDescription": <document>,
"clusterTime": <Timestamp>
}

Database Triggers may enter a suspended state in response to an event that prevents the Trigger's change stream from continuing. Events that can suspend a Trigger include:

  • invalidate events such as dropDatabase, renameCollection, or those caused by a network disruption.

  • the resume token required to resume the change stream is no longer in the cluster oplog. The App logs refer to this as a ChangeStreamHistoryLost error.

In the event of a suspended or failed trigger, Atlas App Services sends the project owner an email alerting them of the issue.

You can configure a Trigger to automatically resume if the Trigger was suspended because the resume token is no longer in the oplog. The Trigger does not process any missed change stream events between when the resume token is lost and when the resume process completes.

When you manually resume a suspended Trigger, your App attempts to resume the Trigger at the next change stream event after the change stream stopped. If the resume token is no longer in the cluster oplog, the Trigger must be started without a resume token. This means the Trigger begins listening to new events but does not process any missed past events.

You can adjust the oplog size to keep the resume token for more time after a suspension by scaling your Atlas cluster. Maintain an oplog size a few times greater than your cluster's peak oplog throughput (GB/hour) to reduce the risk of a suspended trigger's resume token dropping off the oplog before the trigger executes. View your cluster's oplog throughput in the Oplog GB/Hour graph in the Atlas cluster metrics.

You can attempt to restart a suspended Trigger from the App Services UI or by importing an application directory with realm-cli

All Triggers keep track of the last time the Trigger executed, known as the latest execution in the App Services UI. Database Triggers also keep track of the last cluster time processed: the last time the change stream backing that Trigger emitted an event. You can access these timestamps in the list of Triggers that displays when you first navigate to the Triggers section from the sidebar.

The difference between the latest execution and the last cluster time processed represents the latency between when an event occurs in your database, and when the Trigger finishes responding to that event. If latency is consistently large, you can reduce it with the following mitigations:

  • Optimize the Trigger's Linked Function to speed up execution.

  • If your Trigger uses Event Ordering, consider switching ordering off to reduce latency.

  • Add resources by upgrading your MongoDB Atlas cluster.

An online store wants to notify its customers whenever one of their orders changes location. They record each order in the store.orders collection as a document that resembles the following:

{
_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: NumberDecimal("10.99") }
],
shippingLocation: [
{ location: "Memphis", time: ISODate("2018-06-27T18:22:33.243Z") },
]
}

To automate this process, the store creates a database Trigger that listens for UPDATE change events in the store.orders collection. When the trigger observes an UPDATE event, it passes the change event object to its associated Function, textShippingUpdate. The Function checks the change event for any changes to the shippingLocation field and, if it was updated, sends a text message to the customer with the new location of the order.

textShippingUpdate
exports = async function (changeEvent) {
// Destructure out fields from the change stream event object
const { updateDescription, fullDocument } = changeEvent;
// Check if the shippingLocation field was updated
const updatedFields = Object.keys(updateDescription.updatedFields);
const isNewLocation = updatedFields.some(field =>
field.match(/shippingLocation/)
);
// If the location changed, text the customer the updated location.
if (isNewLocation) {
const { customerId, shippingLocation } = fullDocument;
const twilio = context.services.get("myTwilioService");
const mongodb = context.services.get("mongodb-atlas");
const customers = mongodb.db("store").collection("customers");
const { location } = shippingLocation.pop();
const customer = await customers.findOne({ _id: customer_id })
twilio.send({
to: customer.phoneNumber,
from: context.values.get("ourPhoneNumber"),
body: `Your order has moved! The new location is ${location}.`
});
}
};

Consider disabling event ordering if your trigger fires on a collection that receives short bursts of events (e.g. inserting data as part of a daily batch job).

Ordered Triggers wait to execute a Function for a particular event until the Functions of previous events have finished executing. As a consequence, ordered Triggers are effectively rate-limited by the run time of each sequential Trigger function. This may cause a significant delay between the database event and the Trigger firing if a sufficiently large number of Trigger executions are currently in the queue.

Unordered Triggers execute functions in parallel if possible, which can be significantly faster (depending on your use case) but does not guarantee that multiple executions of a Trigger Function occur in event order.

Document preimages use extra information stored in the oplog. The extra data may degrade trigger performance.

Once you've enabled document preimages for any trigger on a given collection, that collection will include preimage data in the oplog and other triggers on the collection can use preimages with no additonal overhead.

You can disable document preimages on a per-trigger basis to exclude the preimage from change events. Regardless of your trigger-level settings, a collection's oplog entries will continue to include preimage data unless you explicitly disable preimages for the collection.

Learn how to view and disable collection-level preimages.

In the Match Expression field, limit the number of Trigger invocations by using Match expressions. The Trigger is only invoked if the document meets the criteria of the $match expression.

Example

The following Match Expression configures a trigger to fire only if the change event object specifies that the status field in a document changed.

{
"updateDescription.updatedFields.status": {
"$exists": true
}
}

In the Project Expression field, limit the number of fields that the Trigger processes by using a $project expression.

Note

Project is inclusive only

When using Triggers, a projection expression is inclusive only. Project does not support mixing inclusions and exclusions. The project expression must be inclusive because Triggers require you to include operationType.

If you want to exclude a single field, the projection expression must include every field except the one you want to exclude. You can only explicitly exclude _id, which is included by default.

Example

A trigger is configured with the following Project Expression:

{
"_id": 0,
"operationType": 1,
"updateDescription.updatedFields.status": 1
}

The change event object that App Services passes to the trigger function only includes the fields specifed in the projection, as in the following example:

{
"operationType": "update",
"updateDescription": {
"updatedFields": {
"status": "InProgress"
}
}
}

For additional examples of Triggers integrated into an App Services App, checkout the example Triggers on Github.

←  Atlas TriggersAuthentication Triggers →
Give Feedback
© 2022 MongoDB, Inc.

About

  • Careers
  • Investor Relations
  • Legal Notices
  • Privacy Notices
  • Security Information
  • Trust Center
© 2022 MongoDB, Inc.