这是一个完整的例子:
class ExampleController @Inject()(database: DefaultDB) extends Controller {
case class Person(firstName: String, lastName: String)
val personCollection: BSONCollection = database.collection("persons")
implicit val PersonJsonReader: Reads[Person] = Json.reads[Person]
implicit val PersonSeqJsonReader: Reads[Seq[Person]] = Reads.seq(PersonJsonReader)
implicit val PersonJsonWriter: Writes[Person] = Json.writes[Person]
implicit val PersonSeqJsonWriter: Writes[Seq[Person]] = Writes.seq(PersonJsonWriter)
implicit val PersonBsonWriter = Macros.writer[Person]
def insertMultiple = Action.async(parse.json) { implicit request =>
val validationResult: JsResult[Seq[Person]] = request.body.validate[Seq[Person]]
validationResult.fold(
invalidValidationResult => Future.successful(BadRequest),
// [1]
validValidationResult => {
val bulkDocs = validValidationResult.
map(implicitly[personCollection.ImplicitlyDocumentProducer](_))
personCollection.bulkInsert(ordered = true)(bulkDocs: _*).map {
case insertResult if insertResult.ok =>
Created(Json.toJson(validationResult.get))
case insertResult =>
InternalServerError
}
}
)
}
}
所有内容都位于 [1] 之后的行中。 validValidationResult 是 Seq[Person] 类型的变量,此时包含有效数据。这就是我们要插入数据库的内容。
为此,我们需要通过将每个文档映射到目标集合的ImplicitlyDocumentProducer(此处为personCollection)来准备文档。剩下的就是bulkDocs 类型的Seq[personCollection.ImplicitlyDocumentProducer]。你可以直接使用bulkInsert():
personCollection.bulkInsert(ordered = true)(bulkDocs: _*)
我们在这里使用 _* 来分解 Seq,因为 bulkInsert() 需要可变参数而不是 Seq。见this thread for more info about it。基本上已经这样了。
剩下的代码正在处理播放结果并验证收到的请求正文以确保它包含有效数据。
以下是一些使用 play/reactivemongo/scala/futures 的一般技巧:
避免Await.result。您基本上在生产代码中永远不需要它。期货背后的想法是执行非阻塞操作。让他们再次使用Await.result 阻止会破坏目的。它对于调试或测试代码很有用,但即便如此,通常也有更好的方法来处理事情。 Scala 期货(不像 java 期货)非常强大,你可以用它们做很多事情,参见例如flatMap/map/filter/foreach/.. 在未来的 scaladoc 中。例如,上面的代码正是利用了这一点。它在控制器方法中使用Action.async 而不是Action。这意味着它必须返回 Future[Result] 而不是 Result。这很棒,因为 ReactiveMongo 会为所有操作返回一堆 Futures。所以你所要做的就是执行bulkInsert,它返回一个Future并使用map()将返回的Future[MultiBulkWriteResult]映射到Future[Result]。这导致没有阻塞,并且可以正常使用返回的未来。
当然上面的例子可以改进一点,我尽量保持简单。
例如,您应该在返回 BadRequest(请求正文验证失败)或 InternalServerError(数据库写入失败)时返回正确的错误消息。您可以从invalidValidationResult 和insertResult 获得有关错误的更多信息。你可以使用 Formats 而不是那么多的读/写(也可以将它们用于 ReactiveMongo)。查看 play json 文档以及响应式 mongo 文档以获取更多信息。