Navigation

MongoDB Data Access

The following actions enable access to a linked MongoDB Atlas cluster from an Android application using the Realm Android SDK.

Note

Each operation described on this page uses a query filter to match certain documents in the collection upon which the operation executes. When a filter matches multiple documents in a collection, they are returned in an indeterminate order unless you specify a sorting parameter. This means that if you do not specify a sort for the findOne(), updateOne(), or deleteOne() functions, your operation could match any document that matches the query filter. For more information on sorting, see cursor.sort().

Set Up Your Project

1

Set Up Your Project

Follow the steps in the Install Realm for Android guide.

2
3

Import Realm Dependencies

For CRUD operations on a remote MongoDB collection, you will use one or more of the following import statements:

// Base Realm Packages
import io.realm.Realm
import io.realm.mongodb.App
import io.realm.mongodb.AppConfiguration
// Realm Authentication Packages
import io.realm.mongodb.User
import io.realm.mongodb.Credentials

// MongoDB Service Packages
import io.realm.mongodb.mongo.MongoClient
import io.realm.mongodb.mongo.MongoDatabase
import io.realm.mongodb.mongo.MongoCollection
// Utility Packages
import org.bson.Document
// Base Realm Packages
import io.realm.Realm;
import io.realm.mongodb.App;
import io.realm.mongodb.AppConfiguration;
// Realm Authentication Packages
import io.realm.mongodb.User;
import io.realm.mongodb.Credentials;

// MongoDB Service Packages
import io.realm.mongodb.mongo.MongoClient;
import io.realm.mongodb.mongo.MongoDatabase;
import io.realm.mongodb.mongo.MongoCollection;
// Utility Packages
import org.bson.Document;
4

Instantiate a MongoDB Collection Handle

Top of Activity File
private lateinit var realmApp: App
private var mongoClient: MongoClient? = null
private lateinit var mongoCollection: MongoCollection<Document>
private lateinit var user: User
private var TAG: String = "EXAMPLE"
In Activity.onCreate()
val appID : String = "<your App ID>" // replace this with your App ID
Realm.init(this) // initialize Realm, required before interacting with SDK
realmApp = App(
   AppConfiguration.Builder(appID)
   .build())

// an authenticated user is required to access a MongoDB instance
val credentials : Credentials = Credentials.anonymous()
realmApp.loginAsync(credentials) {
   if (it.isSuccess) {
       user = realmApp.currentUser()!!
       mongoClient = user.getMongoClient("<atlas service name>")
       if (mongoClient != null) {
           mongoCollection = mongoClient?.getDatabase("<database name>")
               .getCollection("<collection name>")
           Log.v(TAG, "Successfully connected to the MongoDB instance.")
       } else {
           Log.e(TAG, "Error connecting to the MongoDB instance.")
       }
   }
   else {
       Log.e(TAG, "Error logging into the Realm app. Make sure that anonymous authentication is enabled.")
   }
}
Top of Activity File
private App realmApp;
private MongoClient mongoClient;
private MongoCollection<Document> mongoCollection;
private User user;
private String TAG = "EXAMPLE";
In Activity.onCreate()
String appID = "<your App ID>"; // replace this with your App ID
Realm.init(this); // initialize Realm, required before interacting with SDK
realmApp = new App(new AppConfiguration.Builder(appID)
       .build());

// an authenticated user is required to access a MongoDB instance
Credentials credentials = Credentials.anonymous();
realmApp.loginAsync(credentials, it -> {
   if (it.isSuccess()) {
      user = realmApp.currentUser();
      assert user != null;
      MongoClient mongoClient = user.getMongoClient("<atlas service name>");
      if (mongoClient != null) {
         mongoCollection = mongoClient.getDatabase("<database name>").getCollection("<collection name>");
         Log.v(TAG, "Successfully connected to the MongoDB instance.");
      } else {
         Log.e(TAG, "Error connecting to the MongoDB instance.");
      }
   else {
      Log.e(TAG, "Error logging into the Realm app. Make sure that anonymous authentication is enabled.");
   }
 });

Example Data

The following examples operate on a MongoDB collection that describes inventory in a chain of plant stores. Consider the following collection of documents describing various plants for sale in store:

[{"name": "venus flytrap", "sunlight": "full", "color": "white", "type": "perennial", "_partition": "Store 42"},
 {"name": "sweet basil", "sunlight": "partial", "color": "green", "type": "annual", "_partition": "Store 42"},
 {"name": "thai basil", "sunlight": "partial", "color": "green", "type": "perennial", "_partition": "Store 42"},
 {"name": "helianthus", "sunlight": "full", "color": "yellow", "type": "annual", "_partition": "Store 42"},
 {"name": "petunia", "sunlight": "full", "color": "purple", "type": "annual", "_partition": "Store 47"}]

Create Documents

These code snippets demonstrate how to insert one or more documents into a MongoDB collection from a mobile application. Insert operations take a document or documents to add to MongoDB as an argument and return a Task that resolves to an object that contains the results of the execution of the operation.

Insert a Single Document

You can insert a single document using collection.insertOne().

The following snippet inserts a single document describing a “lily of the valley” plant into a collection of documents that describe plants for sale in a group of stores:

val user: User? = app.currentUser()

val mongoClient : MongoClient? = user?.getMongoClient("<mongodb-atlas-service-name>")
val mongoDatabase : MongoDatabase? = mongoClient?.getDatabase("inventory")
val mongoCollection : MongoCollection<Document>? = mongoDatabase?.getCollection("plants")

val plant : Document = Document("name", "lily of the valley")
                          .append("sunlight", "full")
                          .append("color", "white")
                          .append("type", "perennial")
                          .append("_partition", "Store 47")

mongoCollection?.insertOne(plant)?.addOnCompleteListener {
   if (it.isSuccessful) {
      Log.v("EXAMPLE", "successfully inserted a document with id: ${it.result.insertedId}")
   } else {
      Log.e("EXAMPLE", "failed to insert documents with: ${it.exception}")
   }
}
User user = app.currentUser();

MongoClient mongoClient = user.getMongoClient("<mongodb-atlas-service-name>");
MongoDatabase mongoDatabase = mongoClient.getDatabase("inventory");
MongoCollection<Document> mongoCollection  = mongoDatabase.getCollection("plants");

Document plant = new Document("name", "lily of the valley")
       .append("sunlight", "full")
       .append("color", "white")
       .append("type", "perennial")
       .append("_partition", "Store 47");

mongoCollection.insertOne(plant).addOnCompleteListener(task -> {
   if (task.isSuccessful()) {
       BsonObjectId insertedId = task.getResult().getInsertedId().asObjectId();
       Log.v("EXAMPLE", "successfully inserted a document with id " + insertedId);
   } else {
       Log.e("EXAMPLE", "failed to insert document with: ", task.getException());
   }
});

Running this snippet produces output resembling the following:

V/EXAMPLE: successfully inserted a document with id: BsonObjectId{value=5f19...}

Insert Multiple Documents

You can insert multiple documents at the same time using collection.insertMany().

The following snippet inserts three documents describing plants into a collection of documents that describe plants for sale in a group of stores:

val user: User? = app.currentUser()

val mongoClient : MongoClient? = user?.getMongoClient("<mongodb-atlas-service-name>")
val mongoDatabase : MongoDatabase? = mongoClient?.getDatabase("inventory")
val mongoCollection : MongoCollection<Document>? = mongoDatabase?.getCollection("plants")

val plants : List<Document> = Arrays.asList(
           Document("name", "rhubarb")
               .append("sunlight", "full")
               .append("color", "red")
               .append("type", "perennial")
               .append("_partition", "Store 47"),
           Document("name", "wisteria lilac")
               .append("sunlight", "partial")
               .append("color", "purple")
               .append("type", "perennial")
               .append("_partition", "Store 42"),
           Document("name", "daffodil")
               .append("sunlight", "full")
               .append("color", "yellow")
               .append("type", "perennial")
               .append("_partition", "Store 42"))

mongoCollection?.insertMany(plants)?.addOnCompleteListener {
   if (it.isSuccessful) {
      Log.v("EXAMPLE", "successfully inserted ${it.result.insertedIds.size} documents into the collection.")
   } else {
      Log.e("EXAMPLE", "failed to insert documents with: ${it.exception}")
   }
}
User user = app.currentUser();

MongoClient mongoClient = user.getMongoClient("<mongodb-atlas-service-name>");
MongoDatabase mongoDatabase = mongoClient.getDatabase("inventory");
MongoCollection<Document> mongoCollection  = mongoDatabase.getCollection("plants");

List<Document> plants  = Arrays.asList(
       new Document("name", "rhubarb")
               .append("sunlight", "full")
               .append("color", "red")
               .append("type", "perennial")
               .append("_partition", "Store 47"),
       new Document("name", "wisteria lilac")
               .append("sunlight", "partial")
               .append("color", "purple")
               .append("type", "perennial")
               .append("_partition", "Store 42"),
       new Document("name", "daffodil")
               .append("sunlight", "full")
               .append("color", "yellow")
               .append("type", "perennial")
               .append("_partition", "Store 42"));

mongoCollection.insertMany(plants).addOnCompleteListener(task -> {
   if (task.isSuccessful()) {
       int insertedCount = task.getResult().getInsertedIds().size();
       Log.v("EXAMPLE", "successfully inserted " + insertedCount + " documents into the collection.");
   } else {
       Log.e("EXAMPLE", "failed to insert documents with: ", task.getException());
   }
});

Running this snippet produces output resembling the following:

V/EXAMPLE: successfully inserted 3 documents into the collection.

Read Documents

These code snippets demonstrate how to read data stored in a MongoDB collection from a mobile application. Read operations use query filters to specify which documents to return from the database. Read operations return a Task that resolves to either a single matched document (in the case of findOne()), a long numeric value (in the case of count()) or an iterator that allows you to traverse the collection of matched documents (in the case of find()).

Find a Single Document

You can find a single document using collection.findOne().

The following snippet finds a single document from the a collection of documents that describe plants for sale in a group of stores where the plant document’s type field contains the string value “perennial”:

val user: User? = app.currentUser()

val mongoClient : MongoClient? = user?.getMongoClient("<mongodb-atlas-service-name>")
val mongoDatabase : MongoDatabase? = mongoClient?.getDatabase("inventory")
val mongoCollection : MongoCollection<Document>? = mongoDatabase?.getCollection("plants")

val queryFilter : Document = Document("type", "perennial")
mongoCollection?.findOne(queryFilter)?.addOnCompleteListener {
   if (it.isSuccessful) {
      Log.v("EXAMPLE", "successfully found a document: ${it.result}")
   } else {
      Log.e("EXAMPLE", "failed to find document with: ${it.exception}")
   }
}
User user = app.currentUser();

MongoClient mongoClient = user.getMongoClient("<mongodb-atlas-service-name>");
MongoDatabase mongoDatabase = mongoClient.getDatabase("inventory");
MongoCollection<Document> mongoCollection  = mongoDatabase.getCollection("plants");

Document queryFilter  = new Document("type", "perennial");
mongoCollection.findOne(queryFilter).addOnCompleteListener(task -> {
   if (task.isSuccessful()) {
       Document result = task.getResult();
       Log.v("EXAMPLE", "successfully found a document: " + result);
   } else {
       Log.e("EXAMPLE", "failed to find document with: ", task.getException());
   }
});

Running this snippet produces output resembling the following:

V/EXAMPLE: successfully found a document: Document{{_id=5f18..., name=venus flytrap, sunlight=full, color=white, type=perennial, _partition=Store 42}}

Find Multiple Documents

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

The following snippet finds all documents in a collection of documents that describe plants for sale in a group of stores that contain a field named _partition with a value of “Store 42”:

val user: User? = app.currentUser()

val mongoClient : MongoClient? = user?.getMongoClient("<mongodb-atlas-service-name>")
val mongoDatabase : MongoDatabase? = mongoClient?.getDatabase("inventory")
val mongoCollection : MongoCollection<Document>? = mongoDatabase?.getCollection("plants")

val queryFilter : Document = Document("_partition", "Store 42")
val findIterable : FindIterable<Document>? = mongoCollection?.find(queryFilter)

findIterable?.iterator()?.addOnCompleteListener {
   if (it.isSuccessful) {
      Log.v("EXAMPLE", "successfully found all plants for Store 42:")
      it.result.forEach {
         Log.v("EXAMPLE", it.toString())
      }
   } else {
      Log.e("EXAMPLE", "failed to find documents with: ${it.exception}")
   }
}
User user = app.currentUser();

MongoClient mongoClient = user.getMongoClient("<mongodb-atlas-service-name>");
MongoDatabase mongoDatabase = mongoClient.getDatabase("inventory");
MongoCollection<Document> mongoCollection  = mongoDatabase.getCollection("plants");

Document queryFilter  = new Document("_partition", "Store 42");
Task<MongoCursor<Document>> findTask = mongoCollection.find(queryFilter).iterator();

findTask.addOnCompleteListener(task -> {
   if (task.isSuccessful()) {
       MongoCursor<Document> results = task.getResult();
       Log.v("EXAMPLE", "successfully found all plants for Store 42:");
       while (results.hasNext()) {
           Log.v("EXAMPLE", results.next().toString());
       }
   } else {
       Log.e("EXAMPLE", "failed to find documents with: ", task.getException());
   }
});

Running this snippet produces output resembling the following:

V/EXAMPLE: successfully found all plants for Store 42:
V/EXAMPLE: Document{{_id=5f18..., name=venus flytrap, sunlight=full, color=white, type=perennial, _partition=Store 42}}
V/EXAMPLE: Document{{_id=5f18..., name=sweet basil, sunlight=partial, color=green, type=annual, _partition=Store 42}}
V/EXAMPLE: Document{{_id=5f18..., name=thai basil, sunlight=partial, color=green, type=perennial, _partition=Store 42}}
V/EXAMPLE: Document{{_id=5f18..., name=helianthus, sunlight=full, color=yellow, type=annual, _partition=Store 42}}

Count Documents in the Collection

You can count documents in a collection using collection.count(). You can specify an optional query filter to determine which documents to count. If you don’t specify a query, the action counts all documents in the collection.

The following snippet counts the number of documents in a collection of documents that describe plants for sale in a group of stores:

val user: User? = app.currentUser()

val mongoClient : MongoClient? = user?.getMongoClient("<mongodb-atlas-service-name>")
val mongoDatabase : MongoDatabase? = mongoClient?.getDatabase("inventory")
val mongoCollection : MongoCollection<Document>? = mongoDatabase?.getCollection("plants")

mongoCollection?.count()?.addOnCompleteListener {
   if (it.isSuccessful) {
      Log.v("EXAMPLE", "successfully counted, number of documents in the collection: ${it.result}")
   } else {
      Log.e("EXAMPLE", "failed to count documents with: ${it.exception}")
   }
}
User user = app.currentUser();

MongoClient mongoClient = user.getMongoClient("<mongodb-atlas-service-name>");
MongoDatabase mongoDatabase = mongoClient.getDatabase("inventory");
MongoCollection<Document> mongoCollection  = mongoDatabase.getCollection("plants");

mongoCollection.count().addOnCompleteListener(task -> {
   if (task.isSuccessful()) {
       long count = task.getResult();
       Log.v("EXAMPLE", "successfully counted, number of documents in the collection: " + count);
   } else {
       Log.e("EXAMPLE", "failed to count documents with: ", task.getException());
   }
});

Running this snippet produces output resembling the following:

V/EXAMPLE: successfully counted, number of documents in the collection: 5

Update Documents

These code snippets demonstrate how to update data stored in a MongoDB collection from a mobile application. Update operations use query filters 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.

Update a Single Document

You can update a single document using collection.updateOne().

The following snippet updates a single document in a collection of documents that describe plants for sale in a group of stores. This operation queries for a document where the name field contains the value “petunia” and changes the value of the first matched document’s sunlight field to “partial”:

val user: User? = app.currentUser()

val mongoClient : MongoClient? = user?.getMongoClient("<mongodb-atlas-service-name>")
val mongoDatabase : MongoDatabase? = mongoClient?.getDatabase("inventory")
val mongoCollection : MongoCollection<Document>? = mongoDatabase?.getCollection("plants")

val queryFilter : Document = Document("name", "petunia")
val updateDocument : Document = Document("sunlight", "partial")

mongoCollection?.updateOne(queryFilter, updateDocument)?.addOnCompleteListener {
   if (it.isSuccessful) {
      val count : Long = it.result.modifiedCount
      if (count == 1L) {
         Log.v("EXAMPLE", "successfully updated a document.")
      } else {
         Log.v("EXAMPLE", "did not update a document.")
      }
   } else {
      Log.e("EXAMPLE", "failed to update a document with: ${it.exception}")
   }
}
User user = app.currentUser();

MongoClient mongoClient = user.getMongoClient("<mongodb-atlas-service-name>");
MongoDatabase mongoDatabase = mongoClient.getDatabase("inventory");
MongoCollection<Document> mongoCollection  = mongoDatabase.getCollection("plants");

Document queryFilter = new Document("name", "petunia");
Document updateDocument = new Document("sunlight", "partial");

mongoCollection.updateOne(queryFilter, updateDocument).addOnCompleteListener(task -> {
   if (task.isSuccessful()) {
       long count = task.getResult().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.getException());
   }
});

Running this snippet produces output resembling the following:

V/EXAMPLE: successfully updated a document.

Update Multiple Documents

You can update a single document using collection.updateMany().

The following snippet updates multiple documents in a collection of documents that describe plants for sale in a group of stores. This operation queries for documents where the _partition field contains the value “Store 47” and changes the value of the _partition field of each matching document to “Store 51”:

val user: User? = app.currentUser()

val mongoClient : MongoClient? = user?.getMongoClient("<mongodb-atlas-service-name>")
val mongoDatabase : MongoDatabase? = mongoClient?.getDatabase("inventory")
val mongoCollection : MongoCollection<Document>? = mongoDatabase?.getCollection("plants")

val queryFilter : Document = Document("_partition", "Store 47")
val updateDocument : Document = Document("_partition", "Store 51")
mongoCollection?.updateMany(queryFilter, updateDocument)?.addOnCompleteListener {
   if (it.isSuccessful) {
      val count : Long = it.result.modifiedCount
      if (count == 1L) {
         Log.v("EXAMPLE", "successfully updated ${count} documents.")
      } else {
         Log.v("EXAMPLE", "did not update any documents.")
      }
   } else {
      Log.e("EXAMPLE", "failed to update documents with: ${it.exception}")
   }
}
User user = app.currentUser();

MongoClient mongoClient = user.getMongoClient("<mongodb-atlas-service-name>");
MongoDatabase mongoDatabase = mongoClient.getDatabase("inventory");
MongoCollection<Document> mongoCollection  = mongoDatabase.getCollection("plants");

Document queryFilter = new Document("_partition", "Store 47");
Document updateDocument = new Document("_partition", "Store 51");

mongoCollection.updateMany(queryFilter, updateDocument).addOnCompleteListener(task -> {
   if (task.isSuccessful()) {
       long count = task.getResult().getModifiedCount();
       if (count != 0) {
           Log.v("EXAMPLE", "successfully updated " + count + " documents.");
       } else {
           Log.v("EXAMPLE", "did not update any documents.");
       }
   } else {
       Log.e("EXAMPLE", "failed to update documents with: ", task.getException());
   }
});

Running this snippet produces output resembling the following:

V/EXAMPLE: successfully updated 2 documents.

Upsert Documents

If an update operation does not match any document in the collection, you can automatically insert a single new document into the collection that matches the update query by setting the upsert option to true.

The following snippet updates a document in a collection of documents that describe plants for sale in a group of stores or inserts a new document if no document matches the query filter. This operation queries for documents where:

  • the sunlight field has a value of “full”
  • the type field has a value of “perennial”
  • the color field has a value of “green”
  • the _partition field has a value of “Store 47”

Because this snippet sets the upsert option to true, if no document matches the query, MongoDB creates a new document that includes both the query filter and specified updates:

val user: User? = app.currentUser()

val mongoClient : MongoClient? = user?.getMongoClient("<mongodb-atlas-service-name>")
val mongoDatabase : MongoDatabase? = mongoClient?.getDatabase("inventory")
val mongoCollection : MongoCollection<Document>? = mongoDatabase?.getCollection("plants")

val queryFilter : Document = Document("sunlight", "full")
                                .append("type", "perennial")
                                .append("color", "green")
                                .append("_partition", "Store 47")
val updateDocument : Document = Document("name", "sweet basil")
val updateOptions : UpdateOptions = UpdateOptions().upsert(true)
mongoCollection?.updateOne(queryFilter, updateDocument, updateOptions)?.addOnCompleteListener {
   if (it.isSuccessful) {
      if (it.result.upsertedId != null) {
        Log.v("EXAMPLE", "successfully upserted a document with id: ${it.result.upsertedId}")
      } else {
        Log.v("EXAMPLE", "successfully updated a document.")
      }
   } else {
      Log.e("EXAMPLE", "failed to update or insert document with: ${it.exception}")
   }
}
User user = app.currentUser();

MongoClient mongoClient = user.getMongoClient("<mongodb-atlas-service-name>");
MongoDatabase mongoDatabase = mongoClient.getDatabase("inventory");
MongoCollection<Document> mongoCollection  = mongoDatabase.getCollection("plants");

Document queryFilter = new Document("sunlight", "full")
       .append("type", "perennial")
       .append("color", "green")
       .append("_partition", "Store 47");
Document updateDocument = new Document("name", "sweet basil");
UpdateOptions updateOptions = new UpdateOptions().upsert(true);

mongoCollection.updateOne(queryFilter, updateDocument, updateOptions).addOnCompleteListener(task -> {
   if (task.isSuccessful()) {
       if(task.getResult().getUpsertedId() != null) {
           Log.v("EXAMPLE", "successfully upserted a document with id " + task.getResult().getUpsertedId());
       } else {
           Log.v("EXAMPLE", "successfully updated a document.");
       }
   } else {
       Log.e("EXAMPLE", "failed to update or insert document with: ", task.getException());
   }
});

Running this snippet produces output resembling the following:

V/EXAMPLE: successfully upserted a document with id: BsonObjectId{value=5f19...}

Delete Documents

These code snippets demonstrate how to delete documents that are stored in a MongoDB collection from a mobile application. Delete operations use a query filter to specify which documents to delete and return a Task that resolves to an object that contains the results of the execution of the operation.

Delete a Single Document

You can delete a single document from a collection using collection.deleteOne().

The following snippet deletes one document in a collection of documents that describe plants for sale in a group of stores. This operation queries for a document where the color field has a value of “green” and deletes the first document that matches the query:

val user: User? = app.currentUser()

val mongoClient : MongoClient? = user?.getMongoClient("<mongodb-atlas-service-name>")
val mongoDatabase : MongoDatabase? = mongoClient?.getDatabase("inventory")
val mongoCollection : MongoCollection<Document>? = mongoDatabase?.getCollection("plants")

val queryFilter : Document = Document("color", "green")
mongoCollection?.deleteOne(queryFilter)?.addOnCompleteListener {
   if (it.isSuccessful) {
      val count : Long = it.result.deletedCount
      if (count == 1L) {
         Log.v("EXAMPLE", "successfully deleted a document.")
      } else {
         Log.v("EXAMPLE", "did not delete a document.")
      }
   } else {
      Log.e("EXAMPLE", "failed to delete document with: ${it.exception}")
   }
}
User user = app.currentUser();

MongoClient mongoClient = user.getMongoClient("<mongodb-atlas-service-name>");
MongoDatabase mongoDatabase = mongoClient.getDatabase("inventory");
MongoCollection<Document> mongoCollection  = mongoDatabase.getCollection("plants");

Document queryFilter = new Document("color", "green");

mongoCollection.deleteOne(queryFilter).addOnCompleteListener(task -> {
   if (task.isSuccessful()) {
       long count = task.getResult().getDeletedCount();
       if (count == 1) {
           Log.v("EXAMPLE", "successfully deleted a document.");
       } else {
           Log.v("EXAMPLE", "did not delete a document.");
       }
   } else {
       Log.e("EXAMPLE", "failed to delete document with: ", task.getException());
   }
});

Running this snippet produces output resembling the following:

V/EXAMPLE: successfully deleted a document.

Delete Multiple Documents

You can delete multiple items from a collection using collection.deleteMany().

The following snippet deletes all documents in a collection of documents that describe plants for sale in a group of stores that match the query filter that matches documents containing both a sunlight field value of “full” and a type field value of “annual”.

val user: User? = app.currentUser()

val mongoClient : MongoClient? = user?.getMongoClient("<mongodb-atlas-service-name>")
val mongoDatabase : MongoDatabase? = mongoClient?.getDatabase("inventory")
val mongoCollection : MongoCollection<Document>? = mongoDatabase?.getCollection("plants")

val queryFilter : Document = Document("sunlight", "full")
                                .append("type", "annual")
mongoCollection?.deleteMany(queryFilter)?.addOnCompleteListener {
   if (it.isSuccessful) {
       val count : Long = it.result.deletedCount
       if (count != 0L) {
           Log.v("EXAMPLE", "succcessfully deleted ${count} documents.")
       } else {
           Log.v("EXAMPLE", "did not delete any documents.")
       }
   } else {
      Log.e("EXAMPLE", "failed to delete documents with: ${it.exception}")
   }
}
User user = app.currentUser();

MongoClient mongoClient = user.getMongoClient("<mongodb-atlas-service-name>");
MongoDatabase mongoDatabase = mongoClient.getDatabase("inventory");
MongoCollection<Document> mongoCollection  = mongoDatabase.getCollection("plants");

Document queryFilter = new Document("sunlight", "full")
       .append("type", "annual");

mongoCollection.deleteMany(queryFilter).addOnCompleteListener(task -> {
   if (task.isSuccessful()) {
       long count = task.getResult().getDeletedCount();
       if (count != 0) {
           Log.v("EXAMPLE", "successfully deleted " + count + " documents.");
       } else {
           Log.v("EXAMPLE", "did not delete any documents.");
       }
   } else {
       Log.e("EXAMPLE", "failed to delete documents with: ", task.getException());
   }
});

Running this snippet produces output resembling the following:

V/EXAMPLE: succcessfully deleted 2 documents.

Aggregate Documents

These code snippets demonstrate how to configure and run aggregation operations on a collection. Aggregation operations run all documents in a collection through a series of data aggregation stages called an aggregation pipeline that allow you to filter and shape documents as well as collect summary data about groups of related documents.

Aggregation operations accept a list of aggregation stages as input, and return a Task that resolves to a collection of documents processed by the pipeline.

Aggregate Documents in a Collection

You can execute an aggregation pipeline using collection.aggregate().

The following snippet groups all documents in the plants collection by their type value and aggregates a count of the number of each type:

val user: User? = app.currentUser()

val mongoClient : MongoClient? = user?.getMongoClient("<mongodb-atlas-service-name>")
val mongoDatabase : MongoDatabase? = mongoClient?.getDatabase("<database>")
val mongoCollection : MongoCollection<Document>? = mongoDatabase?.getCollection("<collection>")

val pipeline : List<Document> = Arrays.asList(
         Document("\$group", Document("_id", "\$type")
            .append("totalCount", Document("\$sum", 1))))
val aggregationTask : Task<MongoCursor<Document>>? =
   mongoCollection?.aggregate(pipeline)?.iterator()

aggregationTask?.addOnCompleteListener {
   if (it.isSuccessful) {
      Log.v("EXAMPLE", "Plant type counts: ")
      it.result.forEach {
         Log.v("EXAMPLE", it.toString())
      }
   } else {
      Log.e("EXAMPLE", "failed to aggregate documents with: ${it.exception}")
   }
}
User user = app.currentUser();

MongoClient mongoClient = user.getMongoClient("<mongodb-atlas-service-name>");
MongoDatabase mongoDatabase = mongoClient.getDatabase("inventory");
MongoCollection<Document> mongoCollection  = mongoDatabase.getCollection("plants");

List<Document> pipeline = Arrays.asList(
       new Document("$group", new Document("_id", "$type")
               .append("totalCount", new Document("$sum", 1))));

Task<MongoCursor<Document>> aggregationTask = mongoCollection.aggregate(pipeline).iterator();

aggregationTask.addOnCompleteListener(task -> {
   if (task.isSuccessful()) {
       MongoCursor<Document> results = task.getResult();
       Log.d("EXAMPLE", "successfully aggregated the plants by type. Type summary:");
       while (results.hasNext()) {
           Log.v("EXAMPLE", results.next().toString());
       }
   } else {
       Log.e("EXAMPLE", "failed to aggregate documents with: ", task.getException());
   }
});

Running this snippet produces output resembling the following:

V/EXAMPLE: Plant type counts:
V/EXAMPLE: Document{{_id=perennial, totalCount=2}}
V/EXAMPLE: Document{{_id=annual, totalCount=3}}

Aggregation Stages

Filter Documents

You can use the $match stage to filter documents according to a standard query filter.

{
  "$match": {
    "<Field Name>": <Query Expression>,
    ...
  }
}

Example

The following $match stage filters documents to include only those where the type field has a value equal to “perennial”:

{
  "$match": {
    "type": {
      "$eq": "perennial"
    },
  }
}

Group Documents

You can use the $group stage to aggregate summary data for one or more documents. MongoDB groups documents based on the expression defined in the _id field of the $group stage. You can reference a specific document field by prefixing the field name with a $.

{
  "$group": {
    "_id": <Group By Expression>,
    "<Field Name>": <Aggregation Expression>,
    ...
  }
}

Example

The following $group stage arranges documents by the value of their _partition field and calculates the number of plant documents that each unique _partition value appears in.

{
  "$group": {
    "_id": "$_partition",
    "numItems": { "$sum": 1 }
  }
}

Project Document Fields

You can use the $project stage to include or omit specific fields from documents or to calculate new fields using aggregation operators. Projections work in two ways:

  • Explicitly include fields with a value of 1. This has the side-effect of implicitly excluding all unspecified fields.
  • Implicitly exclude fields with a value of 0. This has the side-effect of implicitly including all unspecified fields.

These two methods of projection are mutually exclusive: if you explicitly include fields, you cannot explicitly exclude fields, and vice versa.

Note

The _id field is a special case: it is always included in every query unless explicitly specified otherwise. For this reason, you can exclude the _id field with a 0 value while simultaneously including other fields, like _partition, with a 1. Only the special case of exclusion of the _id field allows both exclusion and inclusion in one $project stage.

{
  "$project": {
    "<Field Name>": <0 | 1 | Expression>,
    ...
  }
}

Example

The following $project stage omits the _id field, includes the name field, and creates a new field named storeNumber. The storeNumber is generated using two aggregation operators:

  1. $split separates the _partition value into two string segments surrounding the space character. For example, the value “Store 42” split in this way returns an array with two elements: “Store” and “42”.
  2. $arrayElemAt selects a specific element from an array based on the second argument. In this case, the value 1 selects the second element from the array generated by the $split operator since arrays index from 0. For example, the value [“Store”, “42”] passed to this operation would return a value of “42”.
{
  "$project": {
    "_id": 0,
    "name": 1,
    "storeNumber": { "$arrayElemAt": [ { "$split": [ "$_partition", " " ] }, 1 ] }
  }
}

Add Fields to Documents

You can use the $addFields stage to add new fields with calculated values using aggregation operators.

Note

$addFields is similar to $project but does not allow you to include or omit fields.

Example

The following $addFields stage creates a new field named storeNumber where the value is the output of two aggregate operators that transform the value of the _partition field.

{
  "$addFields": {
    "storeNumber": { "$arrayElemAt": [ { "$split": [ "$_partition", " " ] }, 1 ] }
  }
}

Unwind Array Values

You can use the $unwind stage to transform a single document containing an array into multiple documents containing individual values from that array. When you unwind an array field, MongoDB copies each document once for each element of the array field but replaces the array value with the array element in each copy.

{
  $unwind: {
    path: <Array Field Path>,
    includeArrayIndex: <string>,
    preserveNullAndEmptyArrays: <boolean>
  }
}

Example

The following $unwind stage creates a new document for each element of the items array in each document. It also adds a field called itemIndex to each new document that specifies the element’s position index in the original array:

{
  "$unwind": {
    "path": "$items",
    "includeArrayIndex": "itemIndex"
   }
}

Consider the following document from the a collection of purchases:

{
  _id: 123,
  customerId: 24601,
  items: [
    { name: "Baseball", quantity: 5 },
    { name: "Baseball Mitt", quantity: 1 },
    { name: "Baseball Bat", quantity: 1 },
  ]
}

If we apply the example $unwind stage to this document, the stage outputs the following three documents:

{
  _id: 123,
  customerId: 24601,
  itemIndex: 0,
  items: { name: "Baseball", quantity: 5 }
}, {
  _id: 123,
  customerId: 24601,
  itemIndex: 1,
  items: { name: "Baseball Mitt", quantity: 1 }
}, {
  _id: 123,
  customerId: 24601,
  itemIndex: 2,
  items: { name: "Baseball Bat", quantity: 1 }
}