Reactive Scala Driver for MongoDB

Asynchronous & Non-Blocking

ReactiveMongo Biːsən

These libraries are intended to replace (at some point after release 1.0) the current BSON library (shipped along with ReactiveMongo driver).

The motivation for that is to fix some issues, to bring multiple API and performance improvements (simpler & better).

BSON types and handlers

The main API library migrates both the BSON value types and the handler typeclasses.

It can be configured in a build.sbt as below.

libraryDependencies += "org.reactivemongo" %% "reactivemongo-bson-api" % "0.18.4"

See Scaladoc

Documents and values

The names of the BSON value types are the same as the current BSON library, except the package that is reactivemongo.api.bson (instead of reactivemongo.bson).

import scala.util.Try
import reactivemongo.api.bson._

val bsonDouble = BSONDouble(12.34D)

val bsonStr = BSONString("foo")

val bsonInt = BSONInteger(2345)

// BSON array: [ 12.34, "foo", 2345 ]
val bsonArray = BSONArray(bsonDouble, bsonStr, bsonInt)

val bsonEmptyDoc: BSONDocument = BSONDocument.empty

/* BSON Document:
{
  'foo': 'bar',
  'lorem': 2,
  'values': [ 12.34, "foo", 2345 ],
  'nested': {
    'position': 1000,
    'score': 1.2
  }
}
*/
val bsonDoc = BSONDocument(
  "foo" -> "bar", // as BSONString
  "lorem" -> 2, // as BSONInteger
  "values" -> bsonArray,
  "nested" -> BSONDocument(
    "position" -> 1000,
    "score" -> 1.2D // as BSONDouble
  )
)

val bsonBin = BSONBinary(Array[Byte](0, 1, 2), Subtype.GenericBinarySubtype)
// See Subtype

val bsonObjectID = BSONObjectID.generate()

val bsonBool = BSONBoolean(true)

val bsonDateTime = BSONDateTime(System.currentTimeMillis())

val bsonRegex = BSONRegex("/foo/bar/", "g")

val bsonJavaScript = BSONJavaScript("lorem(0)")

val bsonJavaScriptWs = BSONJavaScriptWS("bar", BSONDocument("bar" -> 1))

val bsonTimestamp = BSONTimestamp(45678L)

val bsonLong = BSONLong(Long.MaxValue)

val bsonZeroDecimal = BSONDecimal.PositiveZero

val bsonDecimal: Try[BSONDecimal] =
  BSONDecimal.fromBigDecimal(BigDecimal("12.23"))

val bsonNull = BSONNull

val bsonMinKey = BSONMinKey

val bsonMaxKey = BSONMaxKey

The API for BSONDocument has been slightly updated, with the function getAs renamed as getAsOpt (to be consistent with getAsTry).

The traits BSONNumberLike and BSONBooleanLike are also kept in the new API, to generalize the handling of numerical and boolean values.

import scala.util.Try
import reactivemongo.api.bson._

val doc = BSONDocument("ok" -> 1.0D /* BSON double */ )

val bsonNumLike: Try[BSONNumberLike] = doc.getAsTry[BSONNumberLike]("ok")
val intLike: Try[Int] = bsonNumLike.flatMap(_.toInt) // =Success(1)

val bsonBoolLike: Try[BSONBooleanLike] = doc.getAsTry[BSONBooleanLike]("ok")
val boolLike: Try[Boolean] = bsonBoolLike.flatMap(_.toBoolean) // =Success(true)

Reader and writer typeclasses

As for the current BSON library, the new API provides an extensible typeclass mechanism, to define how to get and set data as BSON in a typesafe way.

The names of these typeclasses are unchanged (BSONReader and BSONWriter), except the package that is reactivemongo.api.bson (instead of reactivemongo.bson).

In the current BSON library, BSONReader and BSONWriter are defined with two type parameters:

BSONReader[B <: BSONValue, T]

BSONWriter[T, B <: BSONValue]

The new API has been simplified, with only the T type parameter kept.

import reactivemongo.api.bson._

// read a String from BSON, whatever is the specific BSON value type
def stringReader: BSONReader[String] = ???

Not only it makes the API simpler, but it also allows to read different BSON types as a target Scala type (before only supported for numeric/boolean, using the dedicated typeclasses). For example, the Scala numeric types (BigDecimal, Double, Float, Int, Long) can be directly read from any consistent BSON numeric type (e.g. 1.0 as integer 1), without having to use BSONNumberLike.

The new API is also safer, replacing BSONReader.read and BSONWriter.write respectively with BSONReader.readTry and BSONWriter.writeTry, so that serialization errors can be handle at typelevel.

Like the current BSON library, some specific typeclasses are available (with same names) to read and write using BSON documents: BSONDocumentReader and BSONDocumentWriter.

The new library also provide similar macros, to easily materialized document readers and writers for Scala case classes and sealed traits.

case class Person(name: String, age: Int)

import reactivemongo.api.bson._

val personHandler: BSONDocumentHandler[Person] = Macros.handler[Person]

// Or only ...
val personReader: BSONDocumentReader[Person] = Macros.reader[Person]
val personWriter: BSONDocumentWriter[Person] = Macros.writer[Person]