【问题标题】:How should I handle Filter and Futures in play2 and Scala我应该如何在 play2 和 Scala 中处理过滤器和期货
【发布时间】:2013-06-04 12:30:41
【问题描述】:

我正在尝试学习 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
        }
      }
    }
  }

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

【问题讨论】:

    标签: mongodb scala playframework playframework-2.1


    【解决方案1】:

    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 中,您仍然可以使用其他操作进行组合。

    【讨论】:

    • 您好!谢谢您的回答!我不确定我应该如何使用filteredSet。假设我想在返回 Future[Option[Invite]] 的 sms 上调用 insert 方法。这将使代码返回 Future[Set[Future[Option[Invite]]]] 我想我应该以某种方式变平?或者,也许我应该像您的示例一样返回短信,然后使用 filtersSet.map() ?你会怎么做?
    • Would: val futureInserted : Future[Set[Option[Invite]]] = filteredSet.flatMap { invites => Future.traverse(invites)(insertReview) } 是否是遍历 futureInserted 的好方法?
    【解决方案2】:

    你可以试试这样的:

    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。然后,为了便于理解,我将SetOption[Review] 展平,然后根据flatRevs 集合中的内容过滤smsSet。由于我不知道您的对象模型,我不得不将 flatRevs.find 的 impl 留给您,但这应该很容易。

    【讨论】:

    • 您好!谢谢您的回答!你能帮我理解我应该如何使用 toSave。假设我想对 toSave 执行插入操作并调用 insert 接收邀请保存它并且一切顺利它返回 Future [Option [Invite]]。所以假设我想在最后有一个 Future[Set[Option[Invite]]] 我应该如何编写该方法?也许我想错了?
    猜你喜欢
    • 2016-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-05
    • 2017-09-30
    • 2015-07-17
    • 2016-11-21
    相关资源
    最近更新 更多