Skip to content

Latest commit

 

History

History
329 lines (233 loc) · 7.32 KB

File metadata and controls

329 lines (233 loc) · 7.32 KB

Reactivemongo Shortcuts for Play (with JSON)

Maven Central

Reduce code for the common cases of ReactiveMongo usage in Play framework, Scala language.

Table of Contents

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