KEMBAR78
Play + scala + reactive mongo | PPTX
Play + Scala + Reactive Mongo
Building a “reactive” data-access layer to
mongoDB
About Us
Max Kremer
Trialfire - co-founder
founded in June 2013
Autodesk - cloud solutions architect
Datastay - co-founder
Acquired by Autodesk 2011
Marconi Lanna
Trialfire - lead developer
founded in June 2013
Too many startups since
1996 to list here
Why “reactive”
Classic Synchronous Model:
With a traditional synchronous database driver, each
operation blocks the current thread until a response is
received.
More requests = more threads waiting = poor
scalability
What is “reactive”
Fully non-blocking and asynchronous
I/O operations
Play and async I/O
• Java NIO
• Non-blocking, asynchronous IO
• Process multiple HTTP requests with a single thread
• Large number of concurrent requests can be handled
with a few threads
Example
•A Play controller using a Future result:
package controllers
import play.api.mvc.{Action, Controller}
import concurrent.{ExecutionContext, Future}
import ExecutionContext.Implicits.global
object StuffController extends Controller {
def doStuff( ) = Action {
val someStuff = scala.concurrent.future {
models.Stuff.fetch( )
}
Async {
someStuff.map(value => Ok(value))
}
}
}
A word about Futures
•Represents a value that will be available later
•Execution contexts - think “thread pools”
•Futures are Monads
•Layer of abstraction over multi-threading
Data Access Layer
•Active Record Design Pattern
•Based on Futures
•Model = Case Class + Companion Object
•Stackable Traits
Persistence using Traits
import play.api.libs.json.Json
case class User
( id : Option[BSONObjectID]
, firstName: String
, lastName : String
, email : String
, password : String)
object User extends DataAccess[User] {
def collectionName = “user”
implicit val format = Json.format[User]
}
The Data Access Trait
trait DataAccess[M] {
def collectionName: String
implicit val format: Format[M]
private def db = ReactiveMongoPlugin.db
private def collection = db[JSONCollection](collectionName)
def insert(instance: M): (BSONObjectID, Future[LastError]) = {
val id = BSONObjectID.generate
(id, collection.insert(Json.toJson(instance) ++ id))
}
The Data Access Trait (cont’d)
def update(instance: M): Future[LastError] = {
instance.id map { id =>
collection.update(id, Json.toJson(instance))
} getOrElse Future.successful(LastError(err = Some("Invalid
ID"))
}
def byId(id: BSONObjectID): Future[Option[M]] = {
collection.find(id).cursor.headOption map {
_ flatMap { doc: JsObject =>
doc.asOpt[M]
}
}
}
Pros
•easy compared to sql
•no schemas
•no queries
•no migration
•it just works
conversion from/to json automatically
handled by play json api macros
Cons
•Futures all the way down…
•Futures all the way up, too...
•No joins
Cons (cont’d)
case class Book
( name : String
, author: Author)
case class author(name: String) {
lazy val books: Seq[Book] = Book.byAuthor(this)
}
lazy val books: Future[Seq[Book]] = Book.byAuthor(this)
val books = author.books
author.books map { books =>
...
}
Links
reactive mongo driver:
http://reactivemongo.org/
Play ReactiveMongo plugin:
https://github.com/ReactiveMongo/Play-eactiveMongo
The End
Thanks for listening
Future[Option[Applause]]
max@trialfire.com marconi@trialfire.com
We’re hiring!

Play + scala + reactive mongo

  • 1.
    Play + Scala+ Reactive Mongo Building a “reactive” data-access layer to mongoDB
  • 2.
    About Us Max Kremer Trialfire- co-founder founded in June 2013 Autodesk - cloud solutions architect Datastay - co-founder Acquired by Autodesk 2011 Marconi Lanna Trialfire - lead developer founded in June 2013 Too many startups since 1996 to list here
  • 3.
    Why “reactive” Classic SynchronousModel: With a traditional synchronous database driver, each operation blocks the current thread until a response is received. More requests = more threads waiting = poor scalability
  • 4.
    What is “reactive” Fullynon-blocking and asynchronous I/O operations
  • 5.
    Play and asyncI/O • Java NIO • Non-blocking, asynchronous IO • Process multiple HTTP requests with a single thread • Large number of concurrent requests can be handled with a few threads
  • 6.
    Example •A Play controllerusing a Future result: package controllers import play.api.mvc.{Action, Controller} import concurrent.{ExecutionContext, Future} import ExecutionContext.Implicits.global object StuffController extends Controller { def doStuff( ) = Action { val someStuff = scala.concurrent.future { models.Stuff.fetch( ) } Async { someStuff.map(value => Ok(value)) } } }
  • 7.
    A word aboutFutures •Represents a value that will be available later •Execution contexts - think “thread pools” •Futures are Monads •Layer of abstraction over multi-threading
  • 8.
    Data Access Layer •ActiveRecord Design Pattern •Based on Futures •Model = Case Class + Companion Object •Stackable Traits
  • 9.
    Persistence using Traits importplay.api.libs.json.Json case class User ( id : Option[BSONObjectID] , firstName: String , lastName : String , email : String , password : String) object User extends DataAccess[User] { def collectionName = “user” implicit val format = Json.format[User] }
  • 10.
    The Data AccessTrait trait DataAccess[M] { def collectionName: String implicit val format: Format[M] private def db = ReactiveMongoPlugin.db private def collection = db[JSONCollection](collectionName) def insert(instance: M): (BSONObjectID, Future[LastError]) = { val id = BSONObjectID.generate (id, collection.insert(Json.toJson(instance) ++ id)) }
  • 11.
    The Data AccessTrait (cont’d) def update(instance: M): Future[LastError] = { instance.id map { id => collection.update(id, Json.toJson(instance)) } getOrElse Future.successful(LastError(err = Some("Invalid ID")) } def byId(id: BSONObjectID): Future[Option[M]] = { collection.find(id).cursor.headOption map { _ flatMap { doc: JsObject => doc.asOpt[M] } } }
  • 12.
    Pros •easy compared tosql •no schemas •no queries •no migration •it just works conversion from/to json automatically handled by play json api macros
  • 13.
    Cons •Futures all theway down… •Futures all the way up, too... •No joins
  • 14.
    Cons (cont’d) case classBook ( name : String , author: Author) case class author(name: String) { lazy val books: Seq[Book] = Book.byAuthor(this) } lazy val books: Future[Seq[Book]] = Book.byAuthor(this) val books = author.books author.books map { books => ... }
  • 15.
    Links reactive mongo driver: http://reactivemongo.org/ PlayReactiveMongo plugin: https://github.com/ReactiveMongo/Play-eactiveMongo
  • 16.
    The End Thanks forlistening Future[Option[Applause]] max@trialfire.com marconi@trialfire.com We’re hiring!