Navigation

Set Up the Task Tracker Tutorial Backend

Prerequisites

Before you get started, you’ll need a MongoDB Atlas account and cluster. For details on how to create an account and set up a free M0 cluster, see Get Started with Atlas.

Version 4.4 Required

In order to use Realm Sync, your Atlas cluster must use MongoDB version 4.4. When setting up your cluster, select MongoDB 4.4 - Beta from the dropdown menu under Additional Settings.

A. Create a MongoDB Realm App

To begin, you need to create a new Realm app. A Realm app is a central, server-side configuration that functions as the backend for your application.

1

Start Creating a New App

In MongoDB Atlas, navigate to the project that you want to create the app in. Once in your project, click the Realm tab in the top navigation and then click Create a New App.

../../_images/task-tracker-web-create-new-app.png
2

Name the App

Enter a name for your application. In this tutorial we’ll use the name task-tracker-tutorial, but you can choose another name if you prefer to. Realm app names must be alphanumeric and have fewer than 64 characters.

../../_images/task-tracker-web-name-your-application.png
3
4

Create the App

Click Create Realm Application. Realm will create your new app and automatically redirect you to the app’s dashboard.

B. Define Your Data Model

In MongoDB Realm, all data conforms to schemas that you define. The types described by these schemas make up your app’s data model and are a key part of data access and security. Realm uses your data model to generate GraphQL types and operations as well as to validate reads and writes.

1

Set Up the MongoDB Collections

You define the schemas for all data in your application as rules for collections in a linked MongoDB Atlas cluster. To define rules for a collection, you first need to make the collection available to your Realm app.

For this app, we’ll use three collections: projects, users, and tasks.

Click Rules in the lefthand navigation to navigate to the rules editor. In the left sidebar of the rules editor, find the name of your linked cluster and click the plus button next to it. Realm will prompt you to add a new collection.

For Database Name, enter tracker and for Collection Name, enter tasks. We’ll define our own permissions in a bit, so don’t select any permissions template. Click Add Collection to finish setting up the tracker.tasks collection.

Once complete, repeat this process to set up the tracker.users and tracker.projects collections as well.

../../_images/task-tracker-web-setup-collections.png
2

Define a Schema for Project Documents

We want to group related tasks together into a single project. To do this, we can store metadata for each project in the tracker.projects collection and indicate the project that each task belongs to in the task document.

In the rules editor, select the tracker.projects collection and then click the Schema tab. Paste in the following schema and then click Save.

{
  "title": "Project",
  "bsonType": "object",
  "required": [
    "_id",
    "_partition",
    "name"
  ],
  "properties": {
    "_id": {
      "bsonType": "objectId"
    },
    "_partition": {
      "bsonType": "string"
    },
    "name": {
      "bsonType": "string"
    }
  }
}

Sync Rules

In this project, we primarily use projects to handle security for mobile applications using sync. Task and User documents include a project name as their partition key which allows us to sync tasks for all of a user’s projects.

Data access permissions work differently for synced and non-synced clusters, so you won’t use these partition keys if you only connect through the GraphQL API.

3

Define a Schema for User Documents

We want to store some information for each user of the app in the tracker.users collection, such as their name and avatar image. These documents are separate from Realm’s internal user objects, so we’ll also store each user’s ID value in the user_id field of their document. This lets us identify which document describes a given user later when we want to access their information. To codify this, we’ll use a schema that defines the shape and contents of user documents.

In the rules editor, select the tracker.users collection and then click the Schema tab. Paste in the following schema and then click Save.

{
  "title": "User",
  "required": [
    "_id",
    "_partition",
    "user_id",
    "name"
  ],
  "properties": {
    "_id": {
      "bsonType": "objectId"
    },
    "_partition": {
      "bsonType": "string"
    },
    "user_id": {
      "bsonType": "string"
    },
    "name": {
      "bsonType": "string"
    },
    "image": {
      "bsonType": "string"
    }
  }
}
4

Define a Schema for Task Documents

The core function of a task tracker is to store data about a user’s tasks. In this app, we store the task data as documents in the tracker.tasks collection. Each task has a descriptive name and can have one of three statuses: Open, In Progress, or Closed. Additionally, each task may specify a specific user as its assignee. We’ll use another schema to define the shape and contents of documents in the tasks collection.

In the rules editor, select the tracker.tasks collection and then click the Schema tab. Paste in the following schema and then click Save.

Synced Mobile Apps

If you are building a mobile application, set the bsonType of the assignee field to objectId instead of string.

{
  "title": "Task",
  "required": [
    "_id",
    "_partition",
    "name",
    "status"
  ],
  "properties": {
    "_id": {
      "bsonType": "objectId"
    },
    "_partition": {
      "bsonType": "string"
    },
    "assignee": {
      "bsonType": "string"
    },
    "name": {
      "bsonType": "string"
    },
    "status": {
      "bsonType": "string"
    }
  }
}
5

Define a Relationship Between Tasks and Users

The assignee field of each task contains the user id string of the user that the task is assigned to. We can use this information to define a relationship between documents in the tasks and users collections. This will allow us to write GraphQL operations that can read and modify related documents as if they were a single document.

To define the relationship, ensure you’re editing rules for the tracker.tasks collection and then click the Relationships tab. Click Add a Relationship and define a relationship that points from the assignee property to the user_id property in the tracker.tasks collection.

Synced Mobile Apps

If you are building a mobile application, define the relationship to point to _id instead of user_id.

../../_images/task-tracker-web-add-relationship.png

C. Configure User Authentication

Every request sent to Realm must come from an authenticated user, so we need to have a way for users to create accounts and log in. For this app, we’ll use email/password authentication. Authenticating users has the additional benefit of giving each user a persistent identity that we can associate with their tasks in order to easily find and secure them.

1
2

Enable the Provider

Set the Provider Enabled toggle to on.

../../_images/task-tracker-web-auth-enable.png
3

Configure User Confirmation

For the User Confirmation Method, select Automatically confirm users. As the name suggests, this method automatically confirms new users when they register with a valid email and password.

../../_images/task-tracker-web-auth-confirm.png

Exercise: Support Email Confirmation

Once you’ve finished building the application, consider modifying the app to require new users to confirm their accounts before they log in. To learn how, check out the docs for user confirmation.

4

Configure Password Resets

For the Password Reset Method, select Run a password reset function. This method enables an SDK method that calls a Realm Function to handle the password reset. In this tutorial we won’t worry about password resets, so you can use the default password reset function, resetFunc, which denies all password reset requests.

../../_images/task-tracker-web-auth-reset.png

Exercise: Support Password Resets

Once you’ve finished building the application, consider modifying the app to allow users to reset their passwords. To learn how, check out the docs for password resets.

D. Define Data Access Permissions

GraphQL Client Only

If you plan to use this backend with one or more of the mobile client tutorials (iOS, Android, or React Native), you can skip this section because mobile apps use Realm Sync. Realm Sync has its own permissions model, so the permissions set here will not apply.

Once you’ve defined schemas for User and Task, Realm automatically generates GraphQL types and resolvers that allow you to access data through the GraphQL API. By default, however, all GraphQL queries from a client application will fail.

To allow users to read and write data, you must first define data access rules that determine whether a user has read or write permissions for a given document.

1

Define Roles & Permissions for Tasks

For any given task, a user may be the task’s assignee. We want users to be able to create, modify, and delete tasks for themselves. They should be able to see other users’ tasks but shouldn’t be allowed to create new tasks for other users or delete tasks that don’t belong to them.

To accomplish this, we’ll define two roles for the tasks collection. The isAssignee role applies to tasks where the user’s id is listed in the document’s asignee field and the default role applies to all other tasks.

In the rules editor, select the tracker.tasks collection and then click the Permissions tab. Define two roles for the collection that match the following specifications:

Role Name Permissions Apply When
isAssignee
  • Insert Documents: true
  • Delete Documents: true
  • Read All Fields: true
  • Write All Fields: true
{
  "assignee": "%%user.id"
}
default
  • Insert Documents: false
  • Delete Documents: false
  • Read All Fields: true
  • Write All Fields: false
{}
../../_images/task-tracker-web-roles-tasks.png
2

Define Roles & Permissions for Users

In general, you should give special consideration to what user data is necessary for your application and who can read and modify that data. For this tutorial, we’re not storing any sensitive data so we can allow all users to read any user document. However, we want to prevent users from editing data directly (especially if it’s not their data), so we won’t allow write operations on any document. Instead, we can use server-side system functions to handle updates to user documents.

To accomplish this, we’ll define a single role for the users collection that applies to all requests.

In the rules editor, select the tracker.users collection and then click the Permissions tab. Define a role for the collection that matches the following specification:

Role Name Permissions Apply When
default
  • Insert Documents: false
  • Delete Documents: false
  • Read All Fields: true
  • Write All Fields: false
{}
../../_images/task-tracker-web-roles-users.png

E. Enable Sync

Mobile Clients Only

If you plan to use this backend exclusively with the web client using GraphQL and not with one or more of the mobile client tutorials (iOS, Android, or React Native), you can skip this section. The web client uses GraphQL to work with data, not Realm Sync.

To allow the seamless transfer of data across devices, we enable Realm Sync.

1
2

Configure Sync

Follow the instructions in the Realm UI to configure sync for your cluster.

  1. Select a Cluster to Sync: Realm Sync applies to the entire cluster. Specify which cluster you want to sync in the dropdown.
  2. Choose a Partition Key: Enter _partition for the partition key. The partition key specifies which realm each object belongs to.
  3. Define Permissions: Select “No template” and leave the default, empty Read and Write rules. In a future tutorial, we will explore more complex permissions patterns.
3

Save the Configuration and Enable Sync

Click Enable Sync to enable sync.

F. Define an Authentication Trigger

We want each user to have a corresponding document in the users collection that contains their information. We could create these documents manually for every user, but that approach is prone to errors and adds complexity to your client applications. Instead, we can use a trigger to automatically add a document for each user when they register their acount.

1

Create a New Trigger

To define a new trigger, click Triggers in the lefthand navigation and then click Add a Trigger.

../../_images/task-tracker-web-add-trigger.png
2

Define the Trigger Type

Set the Trigger Type to Authentication and give the trigger a descriptive name. We suggest onNewUser, but you can use any name you like.

../../_images/task-tracker-web-configure-trigger-type.png
3

Configure the Trigger Action

We want the trigger to fire when users register a new account, so set the Action Type to Create. We’re using email/password authentication for this app, so specify Email/Password as the only Provider.

../../_images/task-tracker-web-configure-trigger-event.png
4

Define the Trigger Function

When a new user registers their account, we want to add a document to the tracker.users collection that describes the user. To do that, we’ll use a function that can access the user’s info and inserts a new document for them.

Create a new function named createNewUserDocument and paste in the following code:

exports = async function createNewUserDocument({ user }) {
  const cluster = context.services.get("mongodb-atlas");
  const users = cluster.db("tracker").collection("users");
  return await users.insertOne({
    _partition: "My Project",
    user_id: user.id,
    name: user.data.email,
  });
};

MongoDB Automatically Adds Document IDs

MongoDB automatically adds a new ObjectID to the _id field of documents on insert if the field didn’t already exist.

G. Deploy Your App

At this point your Realm App is fully configured and almost ready to accept requests from client applications. All that’s left to do is to deploy the fully configured app.

Click Deploy in the lefthand navigation and find the current draft at the top of the deployment history table. Click the Review & Deploy Changes button and review the diff to make sure that everything looks correct. When you’re ready to go live, click Deploy.

../../_images/task-tracker-web-deploy-history.png

What’s Next?

You just built a functional task tracker application backend with MongoDB Realm. Great job!

Now that you have a working Realm application, you can follow one of our client application tutorials to connect to your Realm app and manage tasks from a mobile or web application.