我正在努力学习期货和ReactiveMongo。 在我的情况下,我有几个邀请对象,并希望过滤掉数据库中已存在的对象。我不想更新或插入已经在数据库中的那些。因此我创建了一个过滤方法:
过滤方式:
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)
。你会如何过滤并保存这个?
答案 0 :(得分: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})
请注意,您可能只想将短信保存在那里,而不是返回该集。但是我写这篇文章的方式,所有内容都将包含在Future
中,你仍然可以使用其他操作。
答案 1 :(得分: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
。然后,在for-comprehension中,我展平Set
的{{1}},然后根据Option[Review]
Set中的内容过滤掉smsSet
。由于我不知道你的对象模型,我不得不将flatRevs
的impl留给你,但这一点应该很简单。