Модел ReactiveMongo за връщане на създадения mongodb документ в една RESTful заявка

Среда: Играйте! 2.2.3, ReactiveMongo 0.10.0-МОМЕНТНА СНИМКА

Да предположим, че имам страница със списък с документи (да кажем „проекти“) и бутон, който изскача модален диалог с полета за попълване. При натискане на бутона OK страницата изпраща заявка с JSON тяло към бекенда:

{
    name: "Awesome Project", 
    url: "https://github.com/ab/cd", 
    repository: "[email protected]/ab/cd.git", 
    script: "empty"
}

Бекендът насочва заявката към Action, дефиниран така:

  def projectsCollection: JSONCollection = db.collection[JSONCollection]("projects")

  def create = Action.async(parse.json) { request =>
    projectsCollection.insert(request.body) map {
      case LastError(true,_,_,_,Some(doc),_,_) =>  Created(JsObject(List(
        "result" -> JsString("OK") ,
        "doc" -> BSONFormats.toJSON(doc)
      )))
      case LastError(false, err, code, msg, _, _, _) => NotAcceptable(JsObject(List(
        "result" -> JsString("ERROR"),
        "error" -> JsString(err.getOrElse("unknown")),
        "code" -> JsNumber(code.getOrElse[Int](0)),
        "msg" -> JsString(msg.getOrElse("no messsage"))
      )))
    }
  }

Класът LastError case има параметър originalDocument: Option[BSONDocument], който се връща в тялото на отговора на заявката, но това не е документът, който очаквах. Искам документа с попълнено BSONObjectID или поне самото _id.

Опитът да извлека току-що създадения документ ме доведе до задънена улица, защото всичко е увито в Future.

Как да напиша елегантен код, който изпълнява задачата?


person Rajish    schedule 29.10.2013    source източник
comment
Имате ли нужда от достъп до _id в случай на грешка?   -  person sh1ng    schedule 13.11.2013
comment
@sh1ng Не се сетих за това, тъй като този случай е за създаване на нов запис, така че в случай на грешка _id така или иначе не съществува, но да, наличието на _id за неуспешна актуализация или изтриване може да бъде полезно.   -  person Rajish    schedule 13.11.2013


Отговори (3)


Едно възможно решение е сами да генерирате полето _id и да го свържете с тялото на заявката:

val json = Json.obj("_id" -> BSONFormats.toJSON(BSONObjectID.generate)) ++ request.body.as[JsObject]

След това използвайте стойността json като параметър insert и поставете в тялото на успешния резултат.

projectsCollection.insert(json) map {
  case LastError(true,_,_,_,Some(doc),_,_) =>  Created(JsObject(List(
    "result" -> JsString("OK") ,
    "doc" -> BSONFormats.toJSON(doc),
    "project" -> json
  )))
person Rajish    schedule 29.10.2013

Нов съм в Play, scala и reactivemongo, така че, моля, извинете отговора ми, ако е грозен. Въпреки това получих вмъкване, след което започнах работа:

def createUser = Action.async(parse.json) { request =>
/*
 * request.body is a JsValue.
 * There is an implicit Writes that turns this JsValue as a JsObject,
 * so you can call insert() with this JsValue.
 * (insert() takes a JsObject as parameter, or anything that can be
 * turned into a JsObject using a Writes.)
 */
val userResult = request.body.validate[User]
userResult.fold(
errors => {
    Future.successful(
    Result(
        header = ResponseHeader(400, Map(CONTENT_TYPE->"application/json")),
        body = Enumerator(Json.obj("status" ->"KO", "message" -> JsError.toFlatJson(errors)).toString.getBytes())
        ))
},
user => blocking{ 
  // `user` is an instance of the case class `models.User`
  val insertDate = new DateTime()
  val newUser = user.copy(created_at = Some(insertDate) )

  collection.insert(newUser).map { lastError => 
    Logger.debug(s"Successfully inserted with LastError: $lastError")
    val cursor = collection.find(newUser).cursor[User]

     // gather all the JsObjects in a list
val futureUsersList: Future[List[User]] = cursor.collect[List]()


// transform the list into a JsArray
val futureUsersJsonArray: Future[JsArray] = futureUsersList.map { persons =>
  Json.arr(persons)
}

// everything's ok! Let's reply with the array
val res = futureUsersJsonArray.map { persons =>

    Created(persons)
  } 
   Await.result(res, Duration(1000, MILLISECONDS))
}


}

) }

person Jon    schedule 24.10.2014

Аз също съм нов в това, но в reactive-mongo 0.11 те премахнаха структурата LastError в полза на WriteResult. WriteResult наистина има поле originalDocument, но е за съжаление зададено на Няма с коментар „ЗАДАЧА“.

Какво измислих, за да върна създадения документ (минус полето _id),

  def promiseOfWriteResult[T](writeResult:Future[WriteResult])(value:T) = {
    val p = Promise[T]
    writeResult map {
      case ok if ok.ok   => p.success(value)
      case error         => p.failure(error.getCause)
    } recover { // !important
      case x : Throwable => p.failure(x)
    }
    p.future
  }

Това ще се използва като,

promiseOfWriteResult(collection.insert(doc))(doc)
person nlucaroni    schedule 25.08.2015
comment
Каква е целта на това предвид факта, че все още нямате нововмъкнатия идентификатор на обект? - person joesan; 24.10.2015