Tutorial: Build Reverse Search Into Your Application using Triggers and Atlas Search
On this page
- Prerequisites
- Create a New Template App
- Add an Alert Box
- Create the Alert Box Component
- Update the Main View
- Store Alert Terms in Atlas
- Create a New Collection
- Enable Access to the Collection
- Write to the Collection
- Run and Test the App
- Add a Trigger
- Create an Atlas Search Index
- Add a Database Trigger
- Define an Atlas function
- Run and Test the App
- What's Next?
Estimated time to complete: 30 minutes
You can use Atlas App Services with Atlas Triggers and Atlas Search to build features, such as reverse search, on top of your applications. Reverse search lets you store search parameters, and then match new documents to those parameters.
In this tutorial, you start with a pre-built TypeScript mobile application that includes a working React Native application (frontend) and its corresponding App Services App configuration files (backend). This template app is a basic to-do list application that lets users do various things to manage their tasks. To learn more about the template app, see the Tutorial: Atlas Device Sync for React Native.
After you've got the template app running, you'll add a new feature that alerts you when a user creates a task that contains a specific word or phrase. This feature illustrates how you might implement reverse search into your production application. You will use Atlas to store specific terms to be alerted on, and then match new tasks against those terms by using Atlas Triggers and Atlas Search.
The feature includes:
An alert box using the Realm React SDK and @realm/react that:
Lets you enter the terms to be alerted on.
Stores the specified terms in Atlas.
A Database Trigger with a custom Atlas Function that:
Alerts you when a new task contains a term you've entered.
Aggregates and returns related tasks by using an Atlas Search query.
For example, if you want to know when users submit a time-sensitive task,
you might enter a term such as urgent
. Then, when a user adds a task that
contains the term, such as Urgent: complete this task
, you'll be alerted
right away.
Prerequisites
Before you begin:
You must set up your local environment for React Native development. For detailed instructions, see Setting up the development environment in the React Native docs.
This tutorial starts with a Template App. You need an Atlas Account, an API key, and App Services CLI to create a Template App.
You can learn more about creating an Atlas account in the Atlas Getting Started documentation. For this tutorial, you need an Atlas account with a free-tier cluster.
You also need an Atlas API key for the MongoDB Cloud account you wish to log in with. You must be a Project Owner to create a Template App using App Services CLI.
To learn more about installing App Services CLI, see Install App Services CLI. After installing, run the login command using the API key for your Atlas project.
To run Atlas Search queries, ensure that your Atlas cluster runs MongoDB version 4.2 or higher.
Create a New Template App
This tutorial is based on the React Native SDK Flexible Sync Template App named
react-native.todo.flex
. You start with the default app and build new features
on it.
To get the template app up and running on your computer, follow the steps described in the React Native tutorial:
Add an Alert Box
Once you've set up and explored the template app, it's time to write some code to implement the new alerting feature.
In this section, you add an alert box that lets you enter terms that might appear in specific, important, or time-sensitive tasks.
Create the Alert Box Component
In the template app's src/
directory, create a new AlertBox.tsx
file
and add the following code. This file contains the UI form that lets you
enter the terms to be alerted on.
import React, {useState} from 'react'; import {StyleSheet, View} from 'react-native'; import {Text, Input, Button} from 'react-native-elements'; import {COLORS} from './Colors'; type Props = { onSubmit: ({term}: {term: string}) => void; }; export function AlertBox(props: Props): React.ReactElement<Props> { const {onSubmit} = props; const [term, setTerm] = useState(''); return ( <View style={styles.modalWrapper}> <Text h4 style={styles.addItemTitle}> Add Alert Term </Text> <Input placeholder="Enter term" onChangeText={(text: string) => setTerm(text)} autoCompleteType={undefined} /> <Button title="Submit" buttonStyle={styles.saveButton} onPress={() => onSubmit({term})} /> </View> ); } const styles = StyleSheet.create({ modalWrapper: { width: 300, minHeight: 200, borderRadius: 4, alignItems: 'center', }, addItemTitle: { margin: 20, }, saveButton: { width: 280, backgroundColor: COLORS.primary, }, });
Update the Main View
In src/ItemListView.tsx
, import the alert box you just defined
by adding the following line to the top of the file:
import {AlertBox} from './AlertBox';
Then, add the following code to render a button that displays the alert box when clicked:
At the top of the
ItemListView
function block, add auseState()
hook to keep track of the alert box view:src/ItemListView.tsxexport function ItemListView() { const realm = useRealm(); const items = useQuery(Item).sorted('_id'); const user = useUser(); const [showNewItemOverlay, setShowNewItemOverlay] = useState(false); const [showAlertBox, setShowAlertBox] = useState(false); After the
Add To-Do
button in the main view, add anAlerts
button that toggles the alert box overlay:src/ItemListView.tsxreturn ( <SafeAreaProvider> <View style={styles.viewWrapper}> ... <Button title="Add To-Do" buttonStyle={styles.addToDoButton} onPress={() => setShowNewItemOverlay(true)} icon={ <Icon type="material" name={'playlist-add'} style={styles.showCompletedIcon} color="#fff" tvParallaxProperties={undefined} /> } /> <Button title="Alerts" buttonStyle={styles.alertButton} onPress={() => setShowAlertBox(true)} icon={ <Icon type="material" name={'add-alert'} style={styles.showCompletedIcon} color="#fff" tvParallaxProperties={undefined} /> } /> <Overlay isVisible={showAlertBox} onBackdropPress={() => setShowAlertBox(false)}> <AlertBox onSubmit={({term}) => { setShowAlertBox(false); }} /> </Overlay> </View> </SafeAreaProvider> ); To change the size and color of the button, add the following lines to the
styles
block at the bottom of the file:src/ItemListView.tsxconst styles = StyleSheet.create({ ... toggleText: { flex: 1, fontSize: 16, }, alertButton: { backgroundColor: '#808080', borderRadius: 4, margin: 5, } });
Store Alert Terms in Atlas
Now that you've created the frontend component for the alert box, configure the application's backend to store and keep track of your alert terms in Atlas.
Create a New Collection
In the Atlas UI, create a collection to store the terms that users enter in the app:
If you're not already at the Database Deployments page, click the Data Services tab.
For the deployment that's synced to the template app, click Browse Collections.
In the left navigation, click the + icon next to the
todo
database to add a new collection.Name the collection
alerts
, then click Create to save the collection.
Enable Access to the Collection
After creating the collection, you must give your app the necessary permissions
to write to the todo.alerts
collection:
Click the App Services tab.
Click the tile for your app.
In the left navigation under Data Access, click Rules.
Under the
todo
database, click thealerts
collection.In the right dialog box, select the readAndWriteAll preset role.
Click Add preset role to confirm your selection.
By default, your application enables deployment drafts. To manually deploy your changes, click Review Draft & Deploy and then Deploy.
Write to the Collection
Once you've configured write access to the todo.alerts
collection, return
to your application code.
In src/ItemListView.tsx
, add the following lines to the top of the function block
to create a helper function that writes to the collection:
export function ItemListView() { const realm = useRealm(); const items = useQuery(Item).sorted('_id'); const user = useUser(); // addAlert() takes a string input and inserts it as a document in the todo.alerts collection const addAlert = async (text: string) => { const mongodb = user?.mongoClient("mongodb-atlas"); const alertTerms = mongodb?.db("todo").collection("alerts"); await alertTerms?.insertOne({ term: text.toLowerCase() }); };
The addAlert()
function takes a string input and uses the React Native SDK to connect to Atlas and insert the specified alert term
as a document to your collection.
Then, add the following line to the alert box submission handler to call addAlert()
when a user submits an alert term in the app:
<Overlay isVisible={showAlertBox} onBackdropPress={() => setShowAlertBox(false)}> <AlertBox onSubmit={({term}) => { setShowAlertBox(false); addAlert(term); }} /> </Overlay>
Run and Test the App
Your app should now allow users to enter alert terms one at a time to be stored in Atlas.
Rebuild the app and open it. Submit a few terms to be alerted on such as
important
or urgent
. Then, view your documents in the todo.alerts
collection
to confirm that the terms appear in Atlas.
Add a Trigger
Now that you've created the alert box and set up its backing collection, create an Atlas Trigger that alerts you when a new task contains one of your alert terms. Triggers can execute application and database logic in response to a change event. Each trigger links to an Atlas Function that defines the trigger's behavior.
In this section, you create a database trigger that runs whenever a user creates a new task. In the trigger's function, you define:
The message that displays in your application logs.
The database logic, so that the trigger returns the message only when the document contains an alert term.
An Atlas Search query that aggregates other tasks that contain the same alert term.
Create an Atlas Search Index
In order to run Atlas Search queries on your data, you must first create
an Atlas Search index to map the fields
in your collection. In the Atlas UI, create a search index on the todo.Item
collection:
Return to the Database Deployments page by clicking the Data Services tab.
Click the name of the deployment that's synced to the template app, then click the Search tab.
To create your first Atlas Search index, click Create Search Index.
In the Configuration Method page, select Visual Editor and click Next.
Leave the Index Name set to
default
.In the Database and Collection section, find the
todo
database and select theItem
collection.Click Next, then click Create Search Index after you've reviewed your index.
Wait for the index to finish building.
The index should take about one minute to build. When it's finished building, the Status column reads
Active
.
Note
To learn more about Atlas Search indexes, see Create an Atlas Search Index.
Add a Database Trigger
To open the database trigger configuration page in the App Services UI:
Click the App Services tab and select the tile for your app.
In the left navigation menu, click Triggers.
Click Add a Trigger and leave the Trigger type set to Database.
Name the trigger
sendAlerts
.Configure the trigger to listen only for new task documents inserted into the
todo.Item
collection:For the Cluster Name, select the deployment that's synced to the template app.
For the Database Name and Collection Name, select the
todo
database andItem
collection.For the Operation Type, select Insert.
Enable Full Document to include each new report document in the change event passed to the trigger function.
Define an Atlas function
Navigate to the Function section of the trigger configuration page and select + New Function from the drop-down menu. Then, define the trigger's function:
Name the function
triggers/sendAlerts
.Copy the following code into the function body:
functions/triggers/sendAlerts.jsexports = async function(changeEvent) { // Read the summary field from the latest inserted document const fullDocument = changeEvent.fullDocument; const summary = fullDocument.summary; // Connect to your Atlas deployment const mongodb = context.services.get("mongodb-atlas"); // Read task and alert data from collections in the todo database const tasks = mongodb.db("todo").collection("Item"); const alerts = mongodb.db("todo").collection("alerts"); const terms = await alerts.distinct("term"); // Check if the task summary matches any of the terms in the alerts collection for (let i = 0; i < terms.length ; i++) { if (summary.toLowerCase().includes(terms[i])) { console.log("The following task has been added to a to-do list: " + summary + ". You've been alerted because it contains the term, " + terms[i] + "."); // Aggregates any tasks that also contain the term by using an Atlas Search query const query = await tasks .aggregate([ { $search: { compound: { must: [{ phrase: { query: terms[i], path: "summary", }, }], mustNot: [{ equals: { path: "isComplete", value: true, }, }], }, }, }, { $limit: 5, }, { $project: { _id: 0, summary: 1, }, }, ]) .toArray(); relatedTerms = JSON.stringify(query); if (relatedTerms != '[]') { console.log("Related incomplete tasks: " + relatedTerms); } } } }; This JavaScript function returns a message in your application logs when a user enters a task that contains a term stored in the
todo.alerts
collection.The function also includes an Atlas Search query to find other task documents in the
todo.Item
collection that contain the same alert term. The query uses:The $search pipeline stage to query the collection.
The following compound operator clauses:
The $limit stage to limit the output to 5 results.
The $project stage to exclude all fields except
summary
.
Note
To learn more, see Create and Run Atlas Search Queries.
When you're finished, click Save and deploy the trigger.
Run and Test the App
Atlas is now set up to alert you when a user creates a task in the app that contains an alert term.
Rebuild and run the app to make sure everything works. Enter a few tasks that contain an alert term you've previously entered. Then, view your logs to see the output from the trigger. You can filter for your trigger logs by selecting the Triggers type from the drop-down menu.
For example, if one of your alert terms is important
,
the log output for a new task might resemble the following:
Logs: [ "The following task has been added to a to-do list: Complete important tutorial. You've been alerted because it contains the term, important.", "Related incomplete tasks: [ {"summary": "Important: Create template app"}, {"summary": "Add important tasks"}, {"summary": "Make sure to read the documentation. This is important."}]" ]
What's Next?
Extend the alert function to call an external service that can send you a text or an email instead of simply logging. To learn more, see External Dependencies.
Read our Atlas Search documentation to learn more about indexing and querying your Atlas data.
Learn about authentication and scheduled triggers.
Define custom HTTPS Endpoints to create app-specific API routes or webhooks.
Note
Share Feedback
How did it go? Use the Rate this page widget at the bottom right of the page to rate its effectiveness. Or file an issue on the GitHub repository if you had any issues.