3

I have a mongo entry where one field is a list. If entry doesn't exist, I want to add new one. If it exists, I want to append a new element to the list.

At the end I want to return an Ok to the client, but only after the operation was completed successfully. Not a strict requirement, but it's what makes most sense for the user, in my opinion.

This is what I have currently - it works, but on update it overwrites the old list, instead of appending a new element.

def myMethod(value:String, value2:String) = Action {

  Async {
    val myElement = Json.obj(
      "key" -> value2
    )

    val myDBEntry = Json.obj(
      "key" -> value,
      "list" -> List(myElement)
    )

    collection.update(Json.obj("key" -> value), myDBEntry, upsert = true).map(lastError =>
      Ok("Mongo LastError: %s".format(lastError)))
  }
}

In order to check if the list exists and append the element / create a new list, I started with something like (this replaces the collection.update block in previous code):

val futureResult:Future[Option[JsObject]] = collection.find(Json.obj("key" -> value)).one[JsObject]

futureResult.map { result =>

  if (result.isEmpty) {
      collection.insert(myDBEntry).map(lastError =>
        Ok("Mongo LastError: %s".format(lastError)))


  } else {
      //this not the correct command yet - but compiler already fails because method is not returning correct future 
      collection.update(Json.obj("key" -> value), myDBEntry, upsert = true).map(lastError =>
        Ok("Mongo LastError: %s".format(lastError)))
  }


}

But the compiler doesn't seem to like this nesting: "Type mismatch, expected: Future[Result], actual: Future:[Future[SimpleResult[Nothing]]]"

Anyways I feel this way is a bit awkward, and there must be a more elegant way to solve this, but I'm new to Futures and ReactiveMongo and have no idea. How do I solve it?

Edit: I also found this post But I think that's returning the response before the DB operation is finished and I don't want that.

Community
  • 1
  • 1
User
  • 31,811
  • 40
  • 131
  • 232

1 Answers1

4

Try changing this line:

futureResult.map { result =>

To this:

futureResult.flatMap { result =>

When you are performing a map on a future and inside that map block are returning another future you need to use flatMap instead as it will flatten out the nesting.

cmbaxter
  • 35,283
  • 4
  • 86
  • 95