Reactivemongo Shortcuts for Play (with JSON)
Reduce code for the common cases of ReactiveMongo usage in Play framework, Scala language.
Table of Contents
- Install
- Usage
- Methods and properties
- [Field shortcuts] (#field-shortcuts)
Install
Add the library in built.sbt
Play 2.6, Scala 2.11
libraryDependencies += "com.github.andriykuba" % "reactivemongo-shortcuts-play-json" % "2.6.1"
Play 2.5, Scala 2.11
libraryDependencies += "com.github.andriykuba" % "reactivemongo-shortcuts-play-json" % "2.5.19"
Usage
Suppose, we want to get some field from all documents. The "native" ReactiveMongo code will look like:
def native()(implicit mongo: ReactiveMongoApi):Future[List[JsObject]] =
mongo.database
.map(_.collection[JSONCollection](collectionName)).flatMap(_
.find(Json.obj(), Json.obj("field" -> 1))
.cursor[JsObject]()
.collect[List](-1,
Cursor.FailOnError(
(a: List[JsObject], e: Throwable) => Cursor.Fail(e))))
With the Shortcuts it will:
def shortcuts()(implicit mongo: ReactiveMongoApi): Future[List[JsObject]] =
all(Json.obj(), Json.obj("name" -> 1))
The Shortcuts reduce method "chaining" to one call and use Play Framework JSON to work with data.
To start use shortcuts just extend com.github.andriykuba.play.reactivemongo.shortcuts.Collection
object Users extends Collection{
val collectionName = "users"
}
...
val allUsersInLondon = Users.all(Json.obj("city" -> "London"))
ReactiveMongoApi
and ExecutionContext
are passed implicitly to all methods but defineSubCollectionName
. ReactiveMongo is asynchronous, so all methods but defineSubCollectionName
return results wrapped in Future
.
Methods and properties
Collection
collectionName
The name of the collection in MongoDB
defineSubCollectionName
Sugar for creating name of higher detailed collection. For example you need to create a collection of user's page visits and you already have the "users" collection. Good naming are:
users
users.pagevisits
So you can do:
object Users extends Collection{
val collectionName = "users"
}
object UsersPagevisits extends Collection{
val collectionName = "users.pagevisits"
}
Or:
object Users extends Collection{
val collectionName = "users"
}
object UsersPagevisits extends Collection{
val collectionName = Users.defineSubCollectionName("pagevisits")
}
collection
Shortcut for getting a collection from a database.
So this string
mongo.database.map(_.collection[JSONCollection](collectionName))
become as short as
MyCollection.collection()
count
Shortcut for getting a number of documents in the collection.
So this string
mongo.database.map(_.collection[JSONCollection](collectionName)).flatMap(c => c.count())
become as short as
MyCollection.count()
fold
Fold the collection. A start value and a fold function are set with the Folder
case class. Projection and sort can also be used.
val folder = Folder(0, (count: Int, doc: JsObject) => {
count + 1
})
MyCollection.fold(Json.obj("age" -> 20), folder)
foldM
Fold the collection asynchronously. A start value and a fold function are set with the FolderM
case class. Projection and sort can also be used.
val folderM = FolderM(0, (count: Int, doc: JsObject) => {
Future(count + 1)
})
MyCollection.foldM(Json.obj("age" -> 20), folderM)
Document
all
Find all documents. It returns a list of JsObject
. Projection and sort can also be used.
MyCollection.all(Json.obj("age" -> 30))
one
Find zero or one document. It throw an exception if more than one document found. Projection can also be used.
MyCollection.one(Json.obj("name" -> "Adam Smith"))
first
Find zero or one document. It returns first document if more than one document found. Projection and sort can also be used.
MyCollection.first(Json.obj("age" -> 40))
first in a set of collections
Look for the first document in a set of collections with different selects.
Scenario to use - check if there is some document in a set of collection that meets the criteria.
Collection.first(List(
(TrainsCollection, Json.obj("price" -> Json.obj("$lte" -> 100))),
(BusesCollection, Json.obj("price" -> Json.obj("$lte" -> 100))),
(PlanesCollection, Json.obj("price" -> Json.obj("$lte" -> 100)))))
Field
fieldOpt[T]
Get an optional field from a single document. Throw an exception if more than one document is found. Field type T
is obligatory.
MyCollection.fieldOpt[Int](Json.obj("name"->"Adam Smith"), "age")
field[T]
Get a field from a single document. It throws an exception if no document or field are found. Throw an exception if more than one document is found. Field type T
is obligatory.
MyCollection.field[Int](Json.obj("name"->"Adam Smith"), "age")
fieldStringOrEmpty
Get a string field from a single document or empty string if no document or file was found. Throw an exception if more than one document is found.
MyCollection.fieldStringOrEmpty(Json.obj("name"->"Adam Smith"), "address")
Update/Create
update
Update matching document (using findAndModify
). This method is also used for document creation (upsert = true
).
MyCollection.update(
Json.obj("name"->"Adam Smith"),
Json.obj("$set" -> Json.obj("age" -> 80)))
MyCollection.update(
mySelector,
myDocument,
upsert = true)
createUnique
Finds some matching document and creates new document if nothing found. It throws a DocumentAlreadyExists
exception otherwise
MyCollection.createUnique(
Json.obj("name"->"John Silver"),
Json.obj(Json.obj("age" -> 40)))
insert
Inserts a document into the collection and wait for the results.
val document = Json.obj("name"->"Adam Smith")
MyCollection.insert(document)
Remove
remove
Remove matching document (using findAndModify
). Return true
if document was removed or false
if it was not found.
MyCollection.remove(Json.obj("name"->"Adam Smith"))
Field Shortcuts
In beta, look the source code of the FieldShortcuts
object