2013-06-04 48 views
2

我正在嘗試學習Futures和ReactiveMongo。 在我的情況下,我有幾個邀請對象,並希望篩選出已經存在於數據庫中的對象。我不想更新或插入數據庫中已有的數據。因此,我創建了過濾器的方法:我應該如何處理play2和scala中的Filter和Futures

過濾方法:

def isAllowedToReview(invite: Invite): Future[Boolean] = { 
    ReviewDAO.findById(invite.recoId, invite.invitedUserId).map { 
     maybeReview => { 
     maybeReview match { 
      case Some(review) => false 
      case None => true 
     } 
     } 
    } 
    } 

DAO:

def findById(rId: Long, userId: Long): Future[Option[Review]] = findOne(Json.obj("rId" -> recoId, "userId" -> userId)) 

def findOne(query: JsObject)(implicit reader: Reads[T]): Future[Option[T]] = {  
    collection.find(query).one[T] 
} 

,然後調用:

val futureOptionSet: Set[Future[Option[Invite]]] = smsSet.filter(isAllowedToReview) 
save the filtered set somehow... 

這不因爲過濾器期望在工作是Invite => Boolean,但我發送Invite => Future(Boolean)。你會如何過濾並保存這個?

回答

3

smsSet.map(sms => isAllowedToReview(sms).map(b => sms -> b))將具有類型Set[Future[(Invite, Boolean)]]。您應該可以撥打Future.sequence將其變成Future[Set[(Invite, Boolean)]]。然後你可以收集結果.map(_.collect{ case (sms, true) => sms})

所以把一切融合在一起的解決方案可能是這樣的:

val futures = smsSet.map(sms => isAllowedToReview(sms).map(b => sms -> b)) 
val future = Future.sequence(futures) 
val result = future.map(_.collect{ case (sms, true) => sms}) 

當你看到mapsequence您可能能夠重構爲:

val filteredSet = Future.traverse(smsSet){ sms => 
    isAllowedToReview(sms).map(b => sms -> b) 
}.map(_.collect{ case (sms, true) => sms}) 

注意,而不是返回集合,你可能只想在那裏保存你的短信。但是我寫這個的方式,全部都會被封裝在一個Future中,您仍然可以編寫其他操作。

+0

你好!謝謝您的回答!我不確定我瞭解我應該如何使用filteredSet。假設我想在返回Future [Option [Invite]]的sms上調用insert方法。這將使代碼返回Future [Set [Future [Option [Invite]]]],我猜我應該以某種方式扁平化?或者,也許我應該返回您的例子中的短信,然後使用filteredSet.map()?你會怎麼做? – jakob

+0

將會:val futureInserted:Future [Set [Option [Invited]]] = filteredSet.flatMap {} {}} Futureites(invites)(insertReview) }是遍歷futureInserted的不錯方法嗎? – jakob

+0

確實!我認爲它會做到這一點。 – huynhjl

1

你可以嘗試這樣的事:

val revsFut = Future.sequence(smsSet.map(invite => ReviewDAO.findById(invite.recoId, invite.invitedUserId)))  
val toSave = for(revs <- revsFut) yield { 
    val flatRevs = revs.flatten 
    smsSet.filter{ invite => 
    flatRevs.find(review => /*Add filter code here */).isDefined 
    } 
} 

什麼我在這裏做的是先取出組審查在smsSet通過映射的邀請匹配,獲取個別及再測序是爲一單曲Future。然後,在理解中,我將SetSet平整爲Option[Review],然後根據flatRevs設置中的內容來篩選smsSet。因爲我不知道你的對象模型,所以我不得不將的impl留給你,但它應該很容易。

+0

您好!謝謝您的回答!你能幫我理解我應該如何處理保存嗎?假設我想對toSave執行插入操作,並且接收Invite的插入操作將其保存並且一切順利,它會返回Future [Option [Invite]]。因此,讓我說我希望在最後有一個未來[設置[選項[邀請]]]我應該如何撰寫該方法?也許我在想錯? – jakob

相關問題