Reactive Scala Driver for MongoDB

Asynchronous & Non-Blocking

Get started

For the impatient, bellow is a complete example.

First the ReactiveMongo dependencies must be configured. Using SBT, you just have to edit build.sbt and add the driver dependency:

libraryDependencies ++= Seq(
  "org.reactivemongo" %% "reactivemongo" % "0.1x"
)

for Pekko based projects, add the following dependency:

libraryDependencies ++= Seq(
  "org.reactivemongo" %% "reactivemongo-pekko" % "0.1x"
)

Then the following code, from connection to operations on a collection, can be used in your project.

import scala.concurrent.{ ExecutionContext, Future }

import reactivemongo.api.{ Cursor, DefaultDB, MongoConnection, AsyncDriver }
import reactivemongo.api.bson.{
  BSONDocumentWriter, BSONDocumentReader, Macros, document
}

object GetStarted {
  // My settings (see available connection options)
  val mongoUri = "mongodb://localhost:27017/mydb?authMode=scram-sha1"

  import ExecutionContext.Implicits.global // use any appropriate context

  // Connect to the database: Must be done only once per application
  val driver = AsyncDriver()
  val parsedUri = Future.fromTry(MongoConnection parseURI mongoUri)

  // Database and collections: Get references
  val futureConnection = parsedUri.flatMap(driver.connect(_))
  def db1: Future[DefaultDB] = futureConnection.flatMap(_.database("firstdb"))
  def db2: Future[DefaultDB] = futureConnection.flatMap(_.database("anotherdb"))
  def personCollection = db1.map(_.collection("person"))

  // Write Documents: insert or update
  
  implicit def personWriter: BSONDocumentWriter[Person] = Macros.writer[Person]
  // or provide a custom one

  // use personWriter
  def createPerson(person: Person): Future[Unit] =
    personCollection.flatMap(_.insert.one(person).map(_ => {})) 

  def updatePerson(person: Person): Future[Int] = {
    val selector = document(
      "firstName" -> person.firstName,
      "lastName" -> person.lastName
    )

    // Update the matching person
    personCollection.flatMap(_.update.one(selector, person).map(_.n))
  }

  implicit def personReader: BSONDocumentReader[Person] = Macros.reader[Person]
  // or provide a custom one

  def findPersonByAge(age: Int): Future[List[Person]] =
    personCollection.flatMap(_.find(document("age" -> age)). // query builder
      cursor[Person](). // using the result cursor
      collect[List](-1, Cursor.FailOnError[List[Person]]()))
      // ... deserializes the document using personReader

  // Custom persistent types
  case class Person(firstName: String, lastName: String, age: Int)
}

Prerequisites:

We assume that you got a running MongoDB instance. If not, get the latest MongoDB binaries and unzip the archive. Then you can launch the database:

$ mkdir /path/to/data
$ /path/to/bin/mongod --dbpath /path/to/data

This will start a standalone MongoDB instance that stores its data in the data directory and listens on the TCP port 27017.

More: Setup your project

Go further:

  1. Connect to the database
  2. Open database and collections
  3. Write documents (insert, update, remove)
  4. Find documents
  5. Streaming

Next: Connect to the database

Suggest changes