Our website is made possible by displaying online advertisements to our visitors. Please consider supporting us by disabling your ad blocker.

Real-Time Location Changes with MongoDB Realm, Change Streams, and Mapbox

TwitterFacebookRedditLinkedInHacker News

When it comes to modern web applications, interactions often need to be done in real-time. This means that instead of periodically checking in for changes, watching or listening for changes often makes more sense.

Take the example of tracking something on a map. When it comes to package shipments, device tracking, or anything else where you need to know the real-time location, watching for those changes in location is great. Imagine needing to know where your fleet is so that you can dispatch them to a nearby incident?

When it comes to MongoDB, watching for changes can be done through change streams. These change streams can be used in any of the drivers, including front-end applications with MongoDB Realm.

In this tutorial, we’re going to leverage MongoDB Realm change streams. When the location data in our NoSQL documents change, we’re going to update the information on an interactive map powered by Mapbox.

Take the following animated image for example:

Mapbox Updates with MongoDB Change Streams

Rather than building an Internet of Things (IoT) device to track and submit GPS data, we’re going to simulate the experience by directly changing our documents in MongoDB. When the update operations are complete, the front-end application with the interactive map is watching for those changes and responding appropriately.

The Requirements

To be successful with this example, you’ll need to have a few things ready to go prior:

  • A MongoDB Atlas cluster
  • A MongoDB Realm application
  • A Mapbox account

For this example, the data will exist in MongoDB Atlas. Since we’re planning on interacting with our data using a front-end application, we’ll be using MongoDB Realm. A Realm application should be created within the MongoDB Cloud and connected to the MongoDB Atlas cluster prior to exploring this tutorial.

Get started with MongoDB Atlas and Realm for FREE in the MongoDB Cloud.

Mapbox will be used as our interactive map. Since Mapbox is a service, you’ll need to have created an account and have access to your access token.

In the animated image, I’m using the MongoDB Visual Studio Code plugin for interacting with the documents in my collection. You can do the same or use another tool such as Compass, the CLI, or the data explorer within Atlas to get the job done.

Understanding the Document Model for the Location Tracking Example

Because we’re only planning on moving a marker around on a map, the data model that we use doesn’t need to be extravagant. For this example, the following is more than acceptable:

{
    "_id": "5ec44f70fa59d66ba0dd93ae",
    "coordinates": [
        -121.4252,
        37.7397
    ],
    "username": "nraboy"
}

In the above example, the coordinates array has the first item representing the longitude and the second item representing the latitude. We’re including a username to show that we are going to watch for changes based on a particular document field. In a polished application, all users probably wouldn’t be watching for changes for all documents. Instead they’d probably be watching for changes of documents that belong to them.

While we could put authorization rules in place for users to access certain documents, it is out of the scope of this example. Instead, we’re going to mock it.

Building a Real-Time Location Tracking Application with Mapbox and the Realm SDK

Now we’re going to build our client-facing application which consists of Mapbox, some basic HTML and JavaScript, and MongoDB Realm.

Let’s start by adding the following boilerplate code:

<!DOCTYPE html>
<head>
    <script src="https://api.mapbox.com/mapbox-gl-js/v1.10.0/mapbox-gl.js"></script>
    <link href="https://api.mapbox.com/mapbox-gl-js/v1.10.0/mapbox-gl.css" rel="stylesheet" />
    <script src="https://s3.amazonaws.com/stitch-sdks/js/bundles/4.6.0/stitch.js"></script>
</head>
<html>
    <body style="margin: 0">
        <div id="map" style="width: 100vw; height: 100vh"></div>
        <script>
            // Logic here ...
        </script>
    </body>
</html>

The above code sets us up by including the Mapbox and MongoDB Realm SDKs. When it comes to querying MongoDB and interacting with the map, we’re going to be doing that from within the <script> tags.

Within the <script> tags, let’s get started by adding the following:

const client = stitch.Stitch.initializeDefaultAppClient('REALM_APP_ID_HERE');
const db = client.getServiceClient(stitch.RemoteMongoClient.factory, "mongodb-atlas").db("location_services");
mapboxgl.accessToken = "MAPBOX_ACCESS_TOKEN_HERE";

var currentLocationMarker;

The above lines of code are useful for the initialization of our services. You’ll want to swap the app id with your actual Realm app id and the Mapbox access token with your actual Mapbox access token. Both of these can be found within each of the services dashboards.

For this example, I’m going to assume you’re using a location_services database within MongoDB Atlas and a tracking collection within that database.

The currentLocationMarker variable will represent our changing marker that moves around on the map as new data comes in from the MongoDB change stream.

Within the same <script> tags, we can initialize the map for displaying:

let map = new mapboxgl.Map({
    container: "map",
    style: "mapbox://styles/mapbox/streets-v11",
    center: [-121.4252, 37.7397],
    zoom: 9
});

Since the map tiles that compose the map come from a service, we need to wait until the map is ready before we start interacting with it. We can make use of the Mapbox load event to let us know the map is ready:

map.on("load", async () => {
    await client.auth.loginWithCredential(new stitch.AnonymousCredential());
    let currentLocation = (await db.collection("tracking").findOne({ "username": "nraboy" })).coordinates;
    currentLocationMarker = new mapboxgl.Marker().setLngLat(currentLocation).addTo(map);
    const stream = await db.collection("tracking").watch({
        "fullDocument.username": "nraboy"
    });
    stream.onNext(event => {
        currentLocationMarker.setLngLat(event.fullDocument.coordinates);
    });
});

Inside the load event, we are doing anonymous authentication with MongoDB Realm. Remember, we could very easily use a stronger authentication method and have authorization rules, but for this example it’s out of the scope.

Once we’re authenticated to Realm, we execute a findOne operation based on the mock username field on our document. The only data we care about is the coordinates, but we want to make sure it comes from the correct username field.

With the latitude and longitude coordinate information in hand, we can update the marker position.

Up until now, we are just setting the marker to the last known position. This is because when we start watching with a change stream, we won’t receive an initial document. This is why we are doing the findOne first.

This brings us to the change stream:

const stream = await db.collection("tracking").watch({
    "fullDocument.username": "nraboy"
});
stream.onNext(event => {
    currentLocationMarker.setLngLat(event.fullDocument.coordinates);
});

For this particular change stream, we are only watching for documents where the username field matches. In a more polished and realistic example, you could use this to watch for only your own documents. We’re mocking this by hard-coding the value.

When documents with the username field experience some kind of change within Atlas, the marker location will update. This is done without us having to constantly query for updates based on a timer.

Conclusion

You just saw how to use change streams in a client-facing application using the MongoDB Realm SDK. To make our example more attractive, we went with a location tracking scenario, whereas when latitude and longitude locations change in the database, the positions are updated in real-time on a map powered by Mapbox.

If you’d like to give MongoDB Atlas and MongoDB Realm a try, there’s a forever FREE tier available through the MongoDB Cloud.

When it comes to location data and MongoDB, there’s so much more you can do. If you’d like to learn how to create and manage geofences, check out my previous tutorial titled, Location Geofencing with MongoDB, Realm, and Mapbox.

This content first appeared on MongoDB.

Nic Raboy

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in C#, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Unity. Nic writes about his development experiences related to making web and mobile development easier to understand.