2015-04-25 1 views
0

У меня есть коллекция статей, где поля «title» и «публикация» имеют уникальное комбинированное ограничение ключа.Вложенные запросы с ReactiveMongo

При вызове insertOrUpdateArticle (a: Article) сначала попробуйте вставить его, если он попадает в ограничение, он должен обновить статью - при необходимости.

Однако я застрял перед этим. Текущая ошибка:

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

Источник:

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 
    } 
} 

Я не уверен, что делать здесь. Код должен возвращать Future (true), если статья была сохранена или обновлена, в противном случае - false. Есть что-то с реактивными и/или scala фьючерсами, которые я пропускаю здесь.

+0

Насколько я вижу, вы '.map' результат' .insert', который является 'Future [LastError]' с результатом '.one' из' .find', который сам является «Будущим», поэтому он, наконец, поднимает «Будущее [Будущее [T]]». Если вы хотите связать асинхронный результат (aka 'Future [T]'), вы также используете '.flatMap' (например,' futureA.flatMap (res1 => futureB) ') или for-comprenhension (например,' for {res1 <- futureA; res2 <- futureB} yield ???} '). – cchantep

+0

Получаем ту же ошибку с плоской картой, что и с картой, боюсь. Мне нужно реагировать на выздоровление, не зная, как это будет разрешено с пониманием. – Wrench

+1

Позаботьтесь о различии b/w 'recover' &' recoverWith'. Ничего особенного для RM, а состав 'Future'. – cchantep

ответ

0

Использование recoverWith для создания нового будущего является решение, модифицированный код:

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) 
    } 
}