Mobile Bytes #11: MongoDB Remote Data Access from within Mobile App

Hello Realm Enthusiasts, :wave:

I hope you are enjoying working with all things Realm. I took a bit of a break from publishing weekly Realm Bytes so I could focus on some other activities like #100DaysOfCode and my first international stage talk at DevoxxUK From MongoDB to Mobile in 50 min. It was a fun learning experience and I am all in to share if you are interested :smiley:

If you have any topics you would like me to discuss, please let me know by replying to this post.

The data in MongoDB Atlas can be accessed remotely from within the mobile application if required. In this case the data does not need to sync to the device, but this comes with some limitations.

Set Up Project

The setup steps are the same when you create a mobile application and connect it to the cloud. If this is your first time connecting a mobile application to backend, please follow section create a realm app . There are ready-made templates that you can use.

The high-level setup steps for an Android application using Realm Java SDK include:

  • installing the Realm Java SDK (or whatever SDK you using)
  • creating a cluster on the cloud
  • creating a Realm Application
  • copying the generated Realm App Id into your client application.

A code snippet in Java to build your application in the mobile client is as follows.This will vary depending on the SDK you are using. Below is the code for an Android application that can be added to either your Activity or global level Application subclass.


String appID = "YOUR APP ID";

Realm.init(this);

App app = new App(new AppConfiguration.Builder(appID).build());

The next step is to set up Authentication. You can use any authentication provider but I have removed the authentication code for brevity.

To instantiate a local MongoDB collection handle, use the following code:


user = app.currentUser();

//1

MongoClient mongoClient =

user.getMongoClient("mongodb-atlas"); // service for MongoDB Atlas cluster containing custom user data

//2

MongoDatabase mongoDatabase =

mongoClient.getDatabase("sample_airbnb");

MongoCollection<Document> mongoCollection =

mongoDatabase.getCollection("listingsAndReviews");

  1. mongodb-atlas is your Data Source name which can be found from your mongodb cloud account

  1. Sample_airbnb is the database that is part of Atlas data-set and can be loaded by following instructions at Load Sample Data. A screenshot from cloud is as below

Read Documents

Read operations use queries to specify which documents to return from the database. Below is a chart for query and corresponding return value

Query Return Value
findOne() - Task
count() - a long numeric
find() - an iterator for traversal

Find A Single Document


Document queryFilter = new Document("price", 80.00);

mongoCollection.findOne(queryFilter).getAsync(task -> {

if (task.isSuccess()) {

Document resultBack = task.get();

Log.d("EXAMPLE", "successfully found a document: " + resultBack);

} else {

Log.e("EXAMPLE", "failed to find document with: ", task.getError());

}

});

Find Multiple Documents

You can find multiple documents using collection.find().


Document readMultiple = new Document("property_type", "House");

RealmResultTask<MongoCursor<Document>> findTask = mongoCollection.find(readMultiple).iterator();

findTask.getAsync(task -> {

if (task.isSuccess()) {

MongoCursor<Document> results = task.get();

Log.v("EXAMPLE", "successfully found all properties of type House:");

while (results.hasNext()) {

Log.v("EXAMPLE", results.next().toString());

}

} else {

Log.e("EXAMPLE", "failed to find documents with: ", task.getError());

}

});

Update Document

Update operations use queries to specify which documents to update and update operators to describe how to mutate documents that match the query. Update operations return a Task that resolves to an object that contains the results of the execution of the operation.


Document updateFilter = new Document("name", "Ribeira Charming Duplex");

Document updateDocument = new Document("$set", new Document("bedrooms", 4));

mongoCollection.updateOne(updateFilter, updateDocument).getAsync(task -> {

if (task.isSuccess()) {

long count = task.get().getModifiedCount();

if (count == 1) {

Log.v("EXAMPLE", "successfully updated a document.");

} else {

Log.v("EXAMPLE", "did not update a document.");

}

} else {

Log.e("EXAMPLE", "failed to update document with: ", task.getError());

}

});

Use-Cases and Limitations

MongoDB Remote Data Access uses MongoDB Query language to access data from within mobile applications but it has limitations. As you are not syncing the data to a local device, you can only access data when the device is online. There is no offline access to data.

Not all the database commands are available to run when executed from within the mobile application. You can read more on database commands not supported.

This is where Sync is beneficial. It ensures that you have offline access to data and that your update/create commands are synced back to the cloud once the device is online. Realm SDKs also offer a more flexible API to run queries on data saved locally.

To Note:

MongoDB Data Access can work with both Sync enabled or not, but needs permission settings and rule configurations respectively

When Sync is enabled:

When Sync is enabled on a cluster, Sync permissions are taken into consideration when CRUD operations are performed. You need to be careful while performing CRUD operations using MongoDB Query Language as partition value (if required field) will need to be provided.

When Sync is not enabled

When Sync is not enabled, MongoDB Rules for the particular collection you are accessing need to be defined from Rules Tab as below:

If no rules are defined, data access operations will fail with an error similar to:

E/EXAMPLE: failed to find a document with:

SERVICE_UNKNOWN(realm::app::ServiceError:-1): no rule exists for namespace 'sample_airbnb.listingsAndReviews'

at io.realm.internal.network.NetworkRequest.onError(NetworkRequest.java:68)

at io.realm.internal.objectstore.OsJavaNetworkTransport.nativeHandleResponse(Native Method)

at io.realm.internal.objectstore.OsJavaNetworkTransport.handleResponse(OsJavaNetworkTransport.java:98).....

Question

There is .getAsync method and the code snippet above works as described. There is an equivalent Java code I tested with and you can refer to the gist I have created.

I hope the provided information is helpful. I look forward to hearing your experiences or feedback on using MongoDB Data Access.

Cheers, :performing_arts:

3 Likes