Reactive Scala Driver for MongoDB
Asynchronous & Non-Blocking
This Play JSON library provides a JSON serialization pack for ReactiveMongo, based on Play Framework JSON library.
Setup
You can setup this serialization pack by adding the following dependency in your project/Build.scala (or build.sbt).
libraryDependencies ++= Seq(
"org.reactivemongo" %% "reactivemongo-play-json" % "0.11.14"
)
If the dependency for the Play plugin (with the right version) is present, it already provides the JSON support and this JSON serialization pack must not be added as a separate dependency.
Then, the following code enables this JSON serialization pack.
import reactivemongo.play.json._
Documents and values
There is one Play JSON class for most of the BSON types, all in the play.api.libs.json package:
All these JSON types extend JsValue, thus any JSON value can be converted to appropriate BSON value:
| BSON | JSON |
|---|---|
| BSONDocument | JsObject |
| BSONArray | JsArray |
| BSONBinary | JsObject with a $binary JsString field containing the value in hexadecimal representation |
| BSONBoolean | JsBoolean |
| BSONDBPointer | No JSON type |
| BSONDateTime | JsObject with a $date JsNumber field with the timestamp (milliseconds) as value |
| BSONDouble | JsNumber |
| BSONInteger | JsNumber |
| BSONJavaScript | JsObject with a $javascript JsString value representing the JavaScript code |
| BSONLong | JsNumber |
| BSONMaxKey | No JSON type |
| BSONMinKey | No JSON type |
| BSONNull | No JSON type |
| BSONObjectID | JsObject with a $oid JsString field with the stringified ID as value |
| BSONRegex | JsObject with a $regex JsString field with the regular expression, and optionally an $options JsString field with the regex flags (e.g. "i" for case insensitive) |
| BSONString | JsString |
| BSONSymbol | JsObject with a $symbol JsString field with the symbol name as value |
| BSONTimestamp | JsObject with a $time and a $i JsNumber fields |
| BSONUndefined | No JSON type |
Furthermore, the whole library is articulated around the concept of Writes and Reads. These are type classes which purpose is to serialize/deserialize objects of arbitrary types into/from JSON.
Consequently, any type that can be serialized as JSON can be also be serialized as BSON.
A document is represented by JsObject, which is basically an immutable list of key-value pairs. Since it is the most used JSON type, one of the main focuses of the ReactiveMongo Play JSON library is to manage such JsObjects as easy as possible. The encode of such JSON object needs an instance of the typeclass OWrites.
This library provides a specialized collection called reactivemongo.play.json.JSONCollection that deals naturally with JsValue and JsObject. Thanks to it, you can now fetch documents from MongoDB in the JSON format, transform them by removing and/or adding some properties, and send them to the client.
Even better, when a client sends a JSON document, you can validate it and transform it before saving it into a MongoDB collection (coast-to-coast approach).
JSON cursors
The support of Play JSON for ReactiveMongo provides some extensions of the result cursors, as .jsArray() to read underlying data as a JSON array.
import play.api.libs.json._
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import reactivemongo.play.json._
import reactivemongo.play.json.collection.{
JSONCollection, JsCursor
}, JsCursor._
def jsonCollection: JSONCollection = ???
type ResultType = JsObject // any type which is provided a `Writes[T]`
jsonCollection.find(Json.obj()).cursor[ResultType].jsArray()
Run a raw command
The command API can be used with the JSON serialization to execution a JSON object as a raw command.
import scala.concurrent.{ ExecutionContext, Future }
import play.api.libs.json.{ JsObject, Json }
import reactivemongo.play.json._
import reactivemongo.api.commands.Command
def rawResult(db: reactivemongo.api.DefaultDB)(implicit ec: ExecutionContext): Future[JsObject] = {
val commandDoc = Json.obj(
"aggregate" -> "orders", // we aggregate on collection `orders`
"pipeline" -> List(
Json.obj("$match" -> Json.obj("status" -> "A")),
Json.obj(
"$group" -> Json.obj(
"_id" -> "$cust_id",
"total" -> Json.obj("$sum" -> "$amount"))),
Json.obj("$sort" -> Json.obj("total" -> -1))
)
)
val runner = Command.run(JSONSerializationPack)
runner.apply(db, runner.rawCommand(commandDoc)).one[JsObject]
}