ReactiveMongo
Asynchronous IO for MongoDB
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
ReactiveMongo
Talk on ReactiveMongo, given by Tristan Lohman at the DC Scala meetup on June 5th, 2013, hosted by Audax Health
- 3,464