2

我正在尝试学习 Futures 和 ReactiveMongo。在我的情况下,我有几个邀请对象,并且想要过滤掉数据库中已经存在的那些。我不想更新或更新数据库中已经存在的那些。因此我创建了一个过滤方法:

过滤方法:

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

道:

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). 您将如何过滤和保存它?

4

2 回答 2

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

当您看到map并且sequence您可以重构为:

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

请注意,您可能只想将短信保存在那里,而不是返回集合。但是我写这个的方式,所有都将被包裹在 a 中Future,您仍然可以使用其他操作进行组合。

于 2013-06-04T13:31:50.130 回答
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 来获取与邀请匹配的评论集,分别获取每个评论,然后将其排序为一个 singe Future。然后,为了便于理解,我将 of 展平SetOption[Review]然后smsSet根据该flatRevsSet 中的内容过滤掉。由于我不知道您的对象模型,因此我不得不将 impl 留给flatRevs.find您,但在这一点上应该很容易。

于 2013-06-04T13:31:39.803 回答