ReactiveMongo

Asynchronous IO for MongoDB



http://slid.es/tristanlohman/reactivemongo

MongoDB

  • Document (JSON)
  • High Performance
  • Scalable
  • humongous

Casbah

  • Based on Java Driver
  • Synchronous

ReactiveMongo

  • Pure Scala
  • Fully¬†Asynchronous
  • Low level

Basics

val mongo = new MongoDriver
val connection = mymongo.connection(List("localhost"))
val db = myConnection.db("rmDemo")
val users = db.collection[BSONDocument]("users")
Plugin for Play2 framework

CRUD

  • Create
  • Read
  • Update
  • Delete

CRUD

Create

 users.insert(BSONDocument("name" -> name, "age" -> 28))
 def insert[T](document: T, ...)(...): Future[LastError]
 users.insert(BSONDocument("name" -> name, "age" -> 28))
   .map(lastError => println(lastError.ok))

CRUD

Delete

 users.remove(BSONDocument("name" -> "Tristan"))
      .map(lastError => println(lastError.ok))

CRUD

Update

users.update(
  BSONDocument("name" -> name),
  BSONDocument("$inc" -> BSONDocument("age" -> 1))
)
.map(lastError => lastError.updated)
  • Upsert
  • Multi

CRUD

Find

 val cursor =
users.find(BSONDocument("name" -> "Tristan")).cursor[BSONDocument]
:Cursor[BSONDocument]

CRUD

Find

  • cursor.toList returns a Future[List[BSONDocument]]
    • Loads the entire dataset into memory
  • cursor.iterator returns an Iterator[BSONDocument]
    • onDemand
  • cursor.enumerate returns play2 style Enumerator

BSONDocument

  • Pretty much JSON
  • Immutable
  • Access to Data
case class User(name: String, age: Int)

BSONDocumentReader[T]

BSONDocument => DomainObject
def read(bson: BSONDocument): User =
  User(
    bson.getAs[String]("name").get,
    bson.getAs[Int]("age").get)

BSONDocumentWriter[T]

Domain Object => BSONDocument
def write(user: User): BSONDocument =
  BSONDocument(
    "name" -> user.name,
    "age" -> user.age)

Domain Object

case class User(name: String, age: Int)
implicit object User
  extends BSONDocumentReader[User] with BSONDocumentWriter[User] {
  def write(user: User): BSONDocument = BSONDocument(
    "name" -> user.name,
    "age" -> user.age
  )

  def read(bson: BSONDocument): User =
    User(bson.getAs[String]("name").get,
      bson.getAs[Int]("age").get)
}

CRUD Revisited

Find
val cursor = users.find(BSONDocument("name" -> name)).cursor[User]
Insert
users.insert(User("Tristan", 28))
  .map(lastError => println(lastError.ok))
Update
users.update(user, BSONDocument("$inc" -> BSONDocument("age" -> 1)))
  .map(lastError => println(lastError.ok))

I already have JSON mappings!


Specialized Collections!

Specialized Collections

Remember
val users = db.collection[BSONCollection]("users")
Lets use Play-JSON
val users = db.collection[JSONCollection]("users")

Domian Object Mapping

Reuse existing mapping
case class User(name: String, age: Int)
implicit val format = Json.format[User]

Putting it All Together

case class User(name: String, age: Int)
implicit val format = Json.format[User]

users.insert(User(name, 28))
  .map(lastError => println(lastError.ok))

val cursor = users.find(Json.obj("age" -> 28)).cursor[User]

users.update(user, Json.obj("$inc" -> Json.obj("age" -> 1)))
  .map(lastError => println(lastError.ok))
  
users.delete(user)
  .map(lastError => println(lastError.ok))

One Json API

Does Other Stuff Good Too!

  • Stream with Iteratees
  • Tail Capped Collections
  • GridFS
  • Aggregation DSL
  • Raw Commands (so anything)

Caveats

  • Not Production Ready
    • 1.0 is just around the corner
  • Scala 2.10 only
  • Dependency on play-iteratee

The End

  • Questions?
  • Comments?
  • Rude Gestures?


ReactiveMongo

By Tristan Lohman

Navigation instructions

Press the space key or click the arrows to the right

ReactiveMongo

Talk on ReactiveMongo, given by Tristan Lohman at the DC Scala meetup on June 5th, 2013, hosted by Audax Health

  • 1,314
Loading comments...