MongoDB Developer
Atlas
plus
Sign in to follow topics
MongoDB Developer Centerchevron-right
Developer Topicschevron-right
Productschevron-right
Atlaschevron-right

A Practical Exercise of Atlas Device SDK for Web With Sync (Preview)

Andy Wang21 min read • Published May 16, 2024 • Updated May 16, 2024
Atlas
Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Table of contents 
  • Atlas Device SDK for web with Device Sync and its real-world usage 
  • Architecture 
  • Basic components
  • Building your own React web app 
    • Step 1: Setting up the back end
    • Step 2: Creating an App Services app 
    • Step 3: Getting ready for Device Sync 
    • Step 4: Atlas Device SDK
    • Step 5: Let the data flow (start using sync)!
  • Implementation of the coffee app
  • A comparison between Device Sync and the Web SDK without Sync
    • What will our web app look like without Device Sync?
    • Which one should we choose?
  • Conclusions
  • Appendix 

Atlas Device SDK for web with Sync and its real-world usage

The Device Sync feature of the Web SDK is a powerful tool designed to bring real-time data synchronization and automatic conflict resolution capabilities to cross-platform applications, seamlessly bridging the gap between users’ back ends and client-side data. It facilitates the creation of dynamic user experiences by ensuring eventual data consistency across client apps with syncing and conflict resolution.
In the real-world environment, certain client apps benefit from a high level of automation, therefore bringing users an intuitive interaction with the client app. For example, a coffee consumption counter web app that allows the user to keep track of the cups of coffee he/she consumes from different devices and dynamically calculates daily coffee intake will create a ubiquitous user experience.
In this tutorial, I will demonstrate how a developer can easily enable Device Sync to the above-mentioned coffee consumption web app. By the end of this article, you will be able to build a React web app that first syncs the cups of coffee you consumed during the day with MongoDB Atlas, then syncs the same data to different devices running the app. However, our journey doesn’t stop here. I will also showcase the difference between the aforementioned Web SDK with Sync (preview) and the Web SDK without automatic syncing when our app needs to sync data with the MongoDB back end. Hopefully, this article will also help you to make a choice between these two options.

Architecture

In this tutorial, we will create two web apps with the same theme: a coffee consumption calculator. The web app that benefits from Device Sync will be named Coffee app Device Sync while the one following the traditional MongoDB client will be named Coffee app.
The coffee app with Device Sync utilizes Atlas Device Sync to synchronize data between the client app and backend server in real time whilst our coffee app without Device Sync relies on the MongoDB driver.
Data synchronization relies on the components below.
  1. App Services: App Services and its Atlas Device SDKs are a suite of development tools optimized for cross-platform devices such as mobile, IoT, and edge, to manage data via MongoDB’s edge database called Realm, which in turn leverages Device Sync. With various SDKs designed for different platforms, Realm enables the possibility of building data-driven applications for multiple mobile devices. The Web SDK we are going to explore in this article is one of the handy tools that help developers build intuitive web app experiences.
  2. User authentication: Before setting up Device Sync, we will need to authenticate a user. In our particular case, for the sake of simplicity, the anonymous method is being used. This procedure allows the sync from the client app to be associated with a specific user account on your backend App Services app.
  3. Schema: You can see schema as the description of how your data looks, or a data model. Schema exists both in your client app’s code and App Services’ UI. You will need to provide the name of it within the configuration.
  4. Sync configuration: It is mandatory to provide the authenticated user, sync mode (flexible: true), and initialSubscriptions which defines a function that sets up initial subscriptions when Realm is opened.
  5. Opening a synced realm: As you will see, we use Realm.open(config); to open a realm that is synchronized with Atlas. The whole process between your client app and back end, as you may have guessed, is bridged by Device Sync.
Once Realm is opened with the configuration we discussed above, any changes to the coffee objects in the local realm are automatically synchronized with Atlas. Likewise, changes made in Atlas are synchronized back to the local realm, keeping the data up-to-date across devices and the server. What’s even better is that the process of data synchronization happens seamlessly in the background without any user action involved.
Device Sync between client device and Atlas
Compared to the Device Sync feature, MongoDB also provides web apps with an alternative option to communicate with the back end. A connection directly to MongoDB services (a.k.a. mongoClient), as the option we will discuss further in this article, provides us with a semi-auto approach for performing CRUD operations.
In a nutshell, using mongoClient to query data gives developers the freedom to initiate CRUD operations under designed situations. For example, you will only want the creation and deletion of data on your local realm to be synced to the back end when the user clicks on a certain button on your app, rather than automatically syncing changes to the server.

Basic components

To build a web application with Device Sync, we will need a few components to start with. I categorized them into two groups: the front end and the back end.
Front end:
  • A React web app, as an interface that bridges the user and back end
  • Realm (for web, all local data is currently stored in memory)
Back end:
  • MongoDB Atlas, as the cloud storage
  • Data (in this article, we will use dummy data)
  • MongoDB App Services app, as the web app’s business logic
These components briefly describe the building blocks of a web app powered by MongoDB App Services. The coffee app is just an example to showcase how Device Sync works and the possibilities for developers to build more complicated apps.

Building your own React web app

In this section, I will provide step-by-step instructions on how to build your own copy of Coffee App. By the end, you will be able to interact with Realm and Device Sync on your own.

Step 1. Setting up the back end

MongoDB Atlas is used as the backend server of the web app. Essentially, Atlas has different tiers, from M0 to M700, which represent the difference in storage size, cloud server performance, and limitations from low to high. For more details on this topic, kindly refer to our documentation.
In this tutorial, we will use the free tier (M0), as it is just powerful enough for learning purposes.
To set up an M0 cluster, you will first need to create an account with MongoDB.
Once the account is ready, we can proceed to “Create a Project.”
Create your project with unique name
You can see “Project” as a container, which can hold multiple clusters and also the datasource of any additional services (e.g., App Services uses Atlas as a datasource). The next step is to select the tier, cloud provider, and region.
Selecting cluster tier on Atlas UI
Note: In production environments, M10 and above are recommended whilst you can configure even higher tiers by setting up advanced configuration options. The self-explanatory website will guide you through further steps, such as setting a username and password for your cluster. These will be the key part for you to access your cluster. After the auto-deployment process has finished, you will see your cluster/database showing up like below.
Database panel within the Atlas UI
Note: Cluster0 is the default name for a newly created cluster. You can give any name to your cluster during the creation process.
We now have a fully functional cluster up and running. Please refer to our tutorial for more details on creating and configuring clusters as this will not be in the scope of this article.

Step 2. Creating an App Services app

App Services (previously named Realm) is a suite of cloud-based tools (i.e., serverless functions, Device Sync, user management, rules) designed to streamline app development with Atlas. In other words, Atlas works as the datasource for App Services.
Our coffee app will utilize App Services in such a way that the back end will provide data sync among client apps.
For this tutorial, we just need to create an empty app. You can easily do so by skipping any template recommendations.
Create an empty App Services app
Once your App Services app has been created, pay attention to the following items:
  • App ID: This is an auto-generated unique parameter and is needed for referencing your app in different scenarios. For example, within the web app’s code, you will need to specify which app your code is working with. In the screenshot below, I defined REALM_APP_ID to be the App Services app I created.
App ID in code
  • Schema: Schema defines how our data looks. In other words, we define a structure of the data we are going to store in the cluster, client devices with specific data types (string, long, etc.), and whether certain properties are required or optional.
Please note: There are also two ways to define schema:
  • Method 1: Populating documents to Atlas and defining schema from the App Services UI
  • Method 2: Defining Object Schema on your client app and using Development Mode to allow configuring data models and queryable fields from the client app
(We will use Method 2 for the example app. Select “Device Sync” on the left-hand side panel and switch on Development Mode. This will allow you to define schema within your client app’s code and then have it applied to the back end automatically.)
For example, let’s define the coffee app’s schema as shown below.
Define server-side coffee drink schema
Alternatively, the App Services UI also provides an easier and more straightforward way to define schema. Select the “Table View” tab to switch between graphical and JSON editor views. Within the table view, App Services will automatically populate your data’s Field Name and let you configure your data in a graphical interface.
Configure schema data type in Table View
Our documentation gives a very good explanation of why schema is a mandatory and important component of Device Sync:
To use Atlas Device Sync, you must define your data model in two formats:
  • App Services schema: This is a server-side schema that defines your data in BSON. Device Sync uses the App Services schema to convert your data to MongoDB documents, enforce validation, and synchronize data between client devices and Atlas.
  • Realm object schema: This is client-side schema of data defined using the Realm SDKs. Each Realm SDK defines the Realm object schema in its own language-specific way. The Realm SDKs use this schema to store data in the Realm database and synchronize data with Device Sync.
Note: As you can see, Development Mode allows your client app to define a schema and have it automatically reflected server-side. (Simply speaking, schema on your server will be modified by the client app.)
As you probably already guessed, this has the potential to mess with your app’s schema and cause serious issues (i.e., stopping Device Sync) in the production environment.
We only use Development Mode for learning purposes and a development environment, hence the name.
By now, we have created an App Services app and configured it to be ready for our coffee app project.

Step 3. Getting ready for Device Sync

We are now ready to implement Device Sync in the coffee app. Sync happens when the following requirements are satisfied.
  • Client devices are connected to the network and have an established connection to the server.
  • The client has data to sync with the server and it initiates a sync session.
  • The client sends IDENT messages to the server. *You can see IDENT messages as an identifier that the client uses to tell the server exactly what Realm file it needs to sync and the status of the client realm (i.e., if the current version is the client realm’s most recently synced server version).
The roadmap below shows the workflow of a web app with the Device Sync feature.
Device Sync roadmap
Next up, let’s look at the basic components of Device Sync.
  1. SDK: A realm SDK is what you will use as a tool kit to work with synced realms.
  2. Data model: See the data model as a description of the data object you want to synchronize between a synced realm and your back end (Atlas). The models include the object type for each object and the structure of the object.
Under the hood, sync is made possible by translating and applying changes between the local realm and the back end. When using Flexible Sync, only the data you subscribe to will be synced. 3. Rules and roles: Rules and roles allow you to define which data (rules) to sync and each user’s ability to read and write data (roles).
To be more specific, rules as a JSON expression dynamically evaluate the input document and decide whether the input can be written/read to object data stored in the back end. Roles evaluate who has the right to perform certain actions to the data (i.e., read/write). They can both be defined within the App Services UI’s “Rules” section.
As an example app, you can configure a collection to be read-only as shown below.
Configure access permission by adding role
One thing worth mentioning specifically here is the data model.
Let’s look at the example of the data model from the coffee app we will be building. The data model can be divided into two parts from a developer’s point of view: the client app data model and the server-side schema.
Server-side schema
The screenshot above shows the document schema for the object we would like to sync, which resides within the back end. The schema is usually auto-generated by App Services. It reflects exactly how the object is structured and the data types of each field. Accordingly, we will need the matching data model defined in our client application’s code.
There are two ways to define the matching object models: Development Mode and the App Services UI.
  • Development Mode: This mode can be enabled within the App Services UI’s “Device Sync” section. What it does is allow you to define the data model first within your client app’s code. Then, App Services will adopt the same data model on the server side. This is a handy feature for developers to build the app and sync experience in a more intuitive way. Please note that this mode should be switched off when the app moves on to the production environment.
Development Mode switch in the App Services UI
  • App Services UI: Alternatively, the App Services UI provides a very useful tool to auto-generate the data model according to the document schema. Even better, you can select the specific programming language you are using for the client app, as shown below.
Auto-generated data model in JS language
With the auto-generated data model code, App Services makes it possible for us to easily integrate this basic component into the client app.
Above is the situation where Device Sync will be triggered, alongside the minimal components we will need to make it work.

Step 4. React and Atlas Device SDKs

We will use React and MongoDB Atlas Device SDK for the coffee app in this article.
Despite the differences in programming languages and functionalities, SDKs share the following common points:
Despite the differences in programming languages and functionalities, SDKs share the following common points:
  • Providing a core database API for creating and working with local databases
  • Providing an API that you need to connect to an Atlas App Services server, and therefore, server-side features like Device Sync, functions, triggers, and authentication will be available at your disposal
We will be using Atlas Device SDK for web later.

Step 5. Let the data flow

Implementation:
Without further ado, I will walk you through the process of creating the coffee app.
Our work here is concentrated on the following parts:
  • App.css — adjusts everything about UI style, color
  • App.js — authentication, data model, business logic, and Sync
  • Footer.js. — add optional information about the developer
  • index.css. — add fonts and web page styling
As mentioned previously, React will be used as the library for our web app. Below are some options you can follow to create the project.
As mentioned previously, React will be used as the library for our web app. Below are some options you can follow to create the project.
Option 1 (the old-fashioned way): Create React App (CRA) has always been an “official” way to start a React project. However, it is no longer recommended in the React documents. The coffee app was originally developed using CRA. However, if you are coming from the older set-up or just wish to see how Device Sync is implemented within a React app, this will still be fine to follow.
Option 2: Vite addresses a major issue with CRA, the cumbersome dependency size, by introducing dependency pre-bundling. It provides lightning-fast, cold-starting performance.
If you already have your project built using CRA, there is also a fast way to make it Vite-compatible by using the code below.
npx nx@latest init
The line above will automatically detect your project’s dependency and structure and make it compatible with Vite. Your application will therefore also enjoy the high performance brought by Vite.
Our simple example app has most of its functionality within the App.js file. Therefore, let’s focus on this one and dive into the details.
(1) Dependency-wise, below are the necessary imports.
Notice realm is being imported above as we need to do this to the source files where we need to interact with the database.
(Consider using the @realm/react package to leverage hooks and providers for opening realms and managing the data. Refer to MongoDB’s other Web Sync Preview example app for how to integrate @realm/react.)
(2)
To link your client app to an App Services app, you will need to supply the App ID within the code. The App ID is a unique identifier for each App Services app, and it will be needed as a reference while working with many MongoDB products.
Note: The client app refers to your actual web app whilst the App Services app refers to the app we create on the cloud, which resides on the Atlas App Services server.
You can easily copy your App ID from the App Services UI.
Left-hand side panel of App Services UI where the user can copy App ID
(3) Now, let’s define the data model within our client app.
As you can see from the above snippet, the data model CoffeeSchema is written in JavaScript, and it looks no different than any other variables. However, it follows what we have in our back end, as shown below.
Auto-generated data model in App Services UI
If this rings a bell, you are totally correct! We discussed two ways to define data models in the previous section. In this case, we use the auto-generated data model from the schema section of the App Services UI. Alternatively, feel free to switch on “Development Mode” within the Device Sync panel and define the data model first in your client app. The server side will automatically adopt the model while this mode is on.
Switching on Development Mode while developing the client app
The caveat here is that Development Mode should almost never be used in a production environment for security reasons.
(4) The core functionality of this web app is realized by Realm and its feature, Device Sync. Therefore, let’s first initiate Realm.
In the code above, we also implemented the following components.
  • credentials: App Services provides multiple authentication methods (anonymous, email/password, API keys, etc.). For simplicity reasons, we are using anonymous as this app’s authentication method. In a real production environment, the authentication method can be quickly switched to .apple, .emailPassword, etc. as listed in the documentation.
  • Sync config: Within the sync block, we supply the information shown below.
user: Passing in the user’s login credentials flexible: Defining what Sync mode the app will use initialSubscriptions: Defining the queries for the data that needs to be synced; the two parameters subs and realm refer to the sync’s subscriptions and local database instance.
We now have built a crucial part that manages the data model used for Sync, authentication, sync mode, and subscription. This part customizes the initial data sync process and tailors it to fit the business logic.
(5) Our coffee app calculates the cups of coffee we consume during the day. The simple app relies on inputs from the user. In this case, the data flowing in and out of the app is the number of different coffees the user consumes.
Coffee drinks quantity tracker UI
The UI here allows the user to increase/decrease the coffee drinks by hitting the - and + rocks. We can build the component like this:
The array of drinksData displays the name and icon of each coffee item.
(6) We now have the functional part of the UI built. However, the icons and buttons won’t do anything now. Let’s implement the logic behind all these UI components.
We will build a function component named Apps() to initialize the app, listen for changes in the coffee drinks amount, and clean up by closing the realm when no longer needed. Here is an overview of the Apps() function component.
Let’s break it down.
On the app’s first launch, useState(null) will initialize the realm variable with a null value. The variable will later be used to save the instance of the opened Realm database.
The latter line creates a piece of state (drinksCount) within a functional component. You can understand drinksCount as a variable that holds the current number of coffee drinks while setDrinksCount is a function which is called to updated the number of drinksCount (a.k.a. state).
In React, we describe the above structure as Hook. The state drinksCount is “hooked by” the function setDrinksCount and gets updated by it. When our user increases/decreases certain coffee drinks on the menu, these two lines are the heroes in the background.
We then use “hook” useEffect to manage the connection to our local realm and listen to the coffee drinks’ changes in their amount.
Notice (1), we use mounted to track whether the local realm is still active and therefore, the risk of updating a closed realm can be avoided.
Notice (2), the “listener” we added responds to local coffee amount changes but that’s not all it does! Thanks to the flexible sync option we already set in the…
… the listener also reacts to changes on the server. Therefore, we can ensure Device Sync works in the background seamlessly.
Next up, let’s create a function to dynamically update the coffee drinks’ number and create new ones if those coffee drinks haven’t already been created in the back end.
First, check whether the realm is initialized.
Then, write to Realm if the specific coffee drink has already been created by searching the coffee object that matches the drinkName.
However, if the coffee drink hasn’t been consumed (created), let’s create it using realm.create.

Summary

Let’s review the process and components implemented in our sample application in order to utilize Realm SDK and its device sync feature.
Initialize realm with the App ID
Open a synced realm
As described in the previous sections, this step contains all the setups, including authentication and sync configuration.
Listen to changes
Keep data updated
This is the journey of our data, from the user’s input to the local realm whilst the data updates are eventually synchronized with the back end (Atlas) with the help of the App Services server, where App Services provides services such as authentication, triggers, and functions.

A comparison of Web SDKs with/without Device Sync

1: What will our web app look like without Device Sync?
To answer this question, first, let’s take a look at the alternative implementation of our coffee app.
The app will still update the changes in coffee consumption to the back end. However, now this is done by using the function updateOne(), as shown by the code snippet below.
Here, we use upsert to update and insert the changed values of specific coffee drinks. As you can see, this code snippet works directly with documents stored in the back end. Instead of opening up a realm with the Device Sync feature, the coffee app without Device Sync still uses Web SDK.
However, the above-described method is also known as “MongoDB Atlas Client.” The name itself is quite self-explanatory as it allows the client application to take advantage of Atlas features and access data from your app directly.
2: Which one should we choose?
Essentially, whether you should use the Device Sync feature from the Web SDK or follow the more traditional Atlas Client depends on your use cases, working environments, and existing codebase. We talked about two different ways to keep data updated between the client apps and the back end. Although both sample apps don’t look very different due to their simple functionality, this will be quite different in more complicated applications.
Look at the UI of both implementations of the web apps:
Web app features Device Sync
Web app features Atlas Client
It is not hard to find the way the user interacts with the app is different. Device Sync no longer requires UI components such as “button” to interact with the user whilst the way the user interacts with the app using Atlas Client looks and feels more traditional. This requires the user’s interaction with different UI components such as buttons, checkboxes, etc.
Imagine an app with much more complex functionalities and UI. If used appropriately, Device Sync has the ability to bring a completely different user experience compared to the app updates data using Atlas Client. For example, a cooking recipe app will be able to show the user different finished products based on the amount/type of ingredients the user selects in real time. Without Device Sync, the app will still serve the same purpose. However, the user needs to confirm his/her choices manually. This won’t be a big issue, but the app loses a part of the intuitive user experience.
When making a choice between Atlas Client and Web SDK’s Device Sync, we need to consider an important aspect, which is the limitations of each method.
At the moment, Web SDK’s Device Sync is in its preview stage. Let’s first discuss the limitations of Device Sync on the web.
  • No persistence: Web SDK doesn’t store sync data to the device’s local disk, which means all local data is stored in memory. Bear in mind that all will be lost when the user closes the browser tab or simply refreshes the web page.
  • No multi-thread support: For now, all Realm operations need to be carried out on the app’s main thread. It isn’t possible to open or work with a realm in a web worker thread. This limitation may cause a slow UI response, which further leads to a negative user experience if not implemented with caution.
This doesn’t necessarily mean Web SDK’s Device Sync feature is an inferior feature. On the contrary, by leveraging server-side functionality (i.e., triggers, functions) we can keep a heavy workload on the App Services server while making sure our web app remains responsive.
  • No encryption at rest: You can understand this limitation as Realm JS Web SDK only encrypts data in transit between the browser and server over HTTPS. Anything that’s saved in the device’s memory will be stored in a non-encrypted format.
However, there’s no need to panic. As previously mentioned, Device Sync uses roles and rules to strictly control users’ access permissions to different data.
A limitation of Atlas Client is the way data is updated/downloaded between the client and server. Compared to Device Sync, Atlas Client does not have the ability to keep data synced automatically. This can also be seen as a feature, in some use cases, where data should only be synced manually.

Conclusion

In this article, we:
  • Talked about the usage of the App Services Web SDK in a React web app.
  • Compared Web SDK’s Device Sync feature against Atlas Client.
  • Discussed which method we should choose.
The completed code examples are available in the appendix below. You can use them as live examples of MongoDB’s App Services Web SDK. As previously mentioned, the coffee apps are designed to be simple and straightforward when it comes to demoing the basic functionality of the Web SDK and its sync feature. It is also easy to add extra features and tailor the app’s source code according to your specific needs. For example:
  1. Instead of anonymous authentication, further configure credentials to use other more secure auth methods, such as email/password.
  2. Modify the data model to fit your app’s theme. For now, our coffee app keeps track of coffee consumption. However, the app can be quickly rebuilt into a recipe app or something similar without complicated modifications and refactoring.
Alternatively, the example apps can also serve as starting points for your own web app project.
App Services’ Web SDK is MongoDB’s answer to developing modern web apps that take advantage of Realm (a local database) and Atlas (a cloud storage solution). Web SDK now supports Device Sync (in preview) whilst before the preview release, Atlas Client allowed web apps to modify and manipulate data on the server. Both of the solutions have the use cases where they are the best fit, and there is no “right answer” that you need to follow.
As a developer, a better choice can be made by first figuring out the purpose of the app and how you would like it to interact with users. If you already have been working on an existing project, it is beneficial to check whether you indeed need the background auto-syncing feature (Device Sync), compared to using queries to perform CRUD operations (Atlas Client). Take a look at our example app and notice the App.js file contains the basic components that are needed for Device Sync to work. Therefore, you will be able to decide whether it is a good idea to integrate Device Sync into your project.

Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Related
Tutorial

Developing a Web Application with Netlify Serverless Functions and MongoDB


Feb 03, 2023 | 6 min read
Article

How to work with Johns Hopkins University COVID-19 Data in MongoDB Atlas


Nov 16, 2023 | 8 min read
Tutorial

Serverless Development with AWS Lambda and MongoDB Atlas Using Java


Jul 20, 2023 | 6 min read
News & Announcements

Unlock the Value of Data in MongoDB Atlas with the Intelligent Analytics of Microsoft Fabric


Nov 17, 2023 | 6 min read
Table of Contents