Play + scala + reactive mongo
-
Upload
max-kremer -
Category
Technology
-
view
6.490 -
download
12
description
Transcript of Play + scala + reactive mongo
Play + Scala + Reactive Mongo
Building a “reactive” data-access layer to mongoDB
About Us
Max Kremer
Trialfire - co-founderfounded in June 2013
Autodesk - cloud solutions architect
Datastay - co-founderAcquired by Autodesk 2011
Marconi Lanna
Trialfire - lead developerfounded 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 Traitsimport 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: Stringimplicit val format: Format[M]
private def db = ReactiveMongoPlugin.dbprivate 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]]
[email protected] [email protected]
We’re hiring!