0

I have an article collection where fields "title" and "publication" has a unique combined key constraint.

When calling insertOrUpdateArticle(a: Article) it will first try to insert it, in case it hits the constraint, it should update the article - if needed.

However, I'm stuck before that. Current error is:

Error:(88, 57) type mismatch;
 found   : scala.concurrent.Future[scala.concurrent.Future[Boolean]]
 required: Boolean
            col_article.find(selector).one[Article].map {

Source:

def insertOrUpdateArticle(a: Article): Future[Boolean] = {
  // try insert article
  col_article.insert[Article](a).map {
    // article inserted
    lastError => {
      println("Article added.")
      true
    }
  }.recover {
    case lastError: LastError =>
      // check if article existed
      lastError.code.get match {
        case 11000 => {
          // article existed (duplicate key error)

          // load old article
          val selector = BSONDocument(
            "title" -> BSONString(a.title),
            "publication" -> BSONString(a.publication)
          )

          col_article.find(selector).one[Article].map {
            case Some(old_a: Article) => {
              // TODO: compare a with old_a
              // TODO: if a differs from old_a, update
              Future(true)
            }
            case None => {
              // something went wrong
              Future(false)
            }
          }
        }
        case _ => {
          println("DB.insertOrUpdateArticle() unexpected error code when inserting: " + lastError.code.get)
          false
        }
      }
    case ex =>
      println("DB.insertOrUpdateArticle() unexpected exception when inserting: " + ex)
      false
  }
}

I'm unsure what to do here. The code should return Future(true) if the article was saved or updated, false otherwise. There's something with reactivemongo and/or scala futures I'm missing out here.

Wrench
  • 4,070
  • 4
  • 34
  • 46
  • As far as I see you `.map` the result of `.insert`, which is a `Future[LastError]` with the result of `.one` from a `.find`, which is itself a `Future`, so it finally raise a `Future[Future[T]]`. If you want to chain async result (aka `Future[T]`) you shoud either use `.flatMap` (e.g. `futureA.flatMap(res1 => futureB)`) or for-comprenhension (e.g. `for { res1 <- futureA; res2 <- futureB } yield ???}`). – cchantep Apr 25 '15 at 14:37
  • Getting the same error with flatMap as with map, I'm afraid. I need to react on recover, not sure how that would be solvable with a for-comprehension. – Wrench Apr 26 '15 at 18:57
  • 1
    Take care to the difference b/w `recover`&`recoverWith`. Nothing specific to RM, but `Future` composition. – cchantep Apr 26 '15 at 21:03
  • @cchantep super, took a trip to Future page at Scala docs and that did the trick, needing to create a new future of course with recoverWith, that did the trick. – Wrench Apr 27 '15 at 07:14

1 Answers1

0

Using recoverWith to create new Future is the solution, modified code:

def insertOrUpdateArticleOld(a: Article): Future[Boolean] = {
  // try insert article
  col_article.insert[Article](a).map {
    // article inserted
    lastError => {
      println("Article added.")
      true
    }
  }.recoverWith {
    case lastError: LastError =>
      // check if article existed
      lastError.code.get match {
        case 11000 => {
          // article existed (duplicate key error)

          // load old article
          val selector = BSONDocument(
            "title" -> BSONString(a.title),
            "publication" -> BSONString(a.publication)
          )

          col_article.find(selector).one[Article].flatMap {
            case Some(old_a: Article) => {
              // TODO: compare a with old_a
              // TODO: if a differs from old_a, update
              Future(true)
            }
            case None => {
              // something went wrong
              Future(false)
            }
          }
        }
        case _ => {
          println("DB.insertOrUpdateArticle() unexpected error code when inserting: " + lastError.code.get)
          Future(false)
        }
      }
    case ex =>
      println("DB.insertOrUpdateArticle() unexpected exception when inserting: " + ex)
      Future(false)
  }
}
Wrench
  • 4,070
  • 4
  • 34
  • 46