Вот полный пример того, как вы можете это сделать:
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: _*)
Мы используем _ * здесь восклицательный знак с послед, так как bulkInsert()
ожидает и с переменным числом аргументов не Seq. См. this thread for more info about it. И это в основном это уже.
Код для повторного воспроизведения обрабатывает результаты воспроизведения и проверяет полученный орган запроса, чтобы убедиться, что он содержит достоверные данные.
Вот несколько общих советов для работы с игры/reactivemongo/SCALA/фьючерсы:
Избегайте Await.result
. В основном он не нужен в производственном коде. Идея фьючерсов заключается в выполнении неблокирующих операций. Заблокировать их снова Await.result
. Это может быть полезно для отладки или тестового кода, но даже тогда есть, как правило, лучшие способы решения проблем. Фьючерсы Scala (в отличие от java) очень мощные, и вы можете много сделать с ними, см., Например, flatMap/map/filter/foreach/.. в будущем scaladoc. Этот код, например, использует именно это. Он использует Action.async
вместо Action
по методу контроллера. Это означает, что он должен вернуть Future[Result]
вместо Result
. Это здорово, потому что ReactiveMongo возвращает кучу фьючерсов для всех операций. Итак, все, что вам нужно сделать, это выполнить bulkInsert
, который возвращает Будущее и использует map()
, чтобы нанести на карту возвращенный Future[MultiBulkWriteResult]
на Future[Result]
. Это не приводит к блокировке, и игра может отлично работать с возвращенным будущим.
Конечно, приведенный выше пример можно немного улучшить, я попытался сохранить его простым. Например, вы должны возвращать правильные сообщения об ошибках при возврате BadRequest (сбой проверки тела запроса) или InternalServerError (сбой записи базы данных). Вы можете получить дополнительную информацию об ошибках от invalidValidationResult
и insertResult
. И вы можете использовать Форматы вместо многих Reads/Writes (а также использовать их для ReactiveMongo).Для получения дополнительной информации об этом загляните в документацию по игре json, а также в реактивный документ mongo.
Спасибо, что определенно прояснил некоторые вещи для меня. Знаете ли вы какие-либо ресурсы для будущего моего понимания. Я родом из mavc-проекта MEAN, и все это превращается из JSON в BSON, а читатели и фьючерсы для меня совершенно новы, а также синтаксис play scala. – Jeff
Да, это во многом. Я предлагаю вам пройти его медленно и проверить документацию для каждого класса или метода/функции, которые вы не знаете. [Play docs] (https://www.playframework.com/documentation/2.5.x/ScalaHome) неплохие, для чтения/записи проверьте главу о json. ReactiveMongo также имеет один для [эквивалента BSON] (http://reactivemongo.org/releases/0.11/documentation/bson/typeclasses.html). Для проверки фьючерсов [этот блогпост] (например, http://danielwestheide.com/blog/2013/01/09/the-neophytes-guide-to-scala-part-8-welcome-to-the-future.html), например , – alextsc
Обратите внимание, что я уже «ленив» в моем примере кода выше, я использую функции макросов, предоставляемые как игровым, так и реактивным монго, для генерации операций чтения/записи. Они могут быть написаны вручную. Не путайте, когда видите это. Это одно и то же, и сначала вы должны практиковать это «вручную». – alextsc