等待将来完成以执行另一个序列

时间:2016-11-07 17:30:07

标签: scala future

我在最后几天遇到了读/写问题,我无法在测试中解决问题。我有一个基于以下模型的JSON文档

package models 

import play.api.libs.json._

object Models {

  case class Record
  (
    id : Int, 
    samples : List[Double]
  )

  object Record {
    implicit val recordFormat = Json.format[Record]
  }
}

我有两个功能:一个用于读取记录,另一个用于更新。

case class MongoIO(futureCollection : Future[JSONCollection]) {

  def readRecord(id : Int) : Future[Option[Record]] = 
    futureCollection
      .flatMap { collection =>
      collection.find(Json.obj("id" -> id)).one[Record]
    }

  def updateRecord(id : Int, newSample : Double) : Future[UpdateWriteResult]= {
    readRecord(id) flatMap { recordOpt =>
      recordOpt match {
        case None =>
          Future { UpdateWriteResult(ok = false, -1, -1, Seq(), Seq(), None, None, None) }
        case Some(record) =>
          val newRecord = 
            record.copy(samples = record.samples :+ newSample)
          futureCollection
          .flatMap { collection =>
            collection.update(Json.obj("id" -> id), newRecord)
          }
      }
    }
  }
}

现在,我有一个List[Future[UpdateWriteResult]]对应于文档上的许多更新,但我想要的是:等待将来完成执行第二个然后等待第二个完成执行第三个。我尝试用这样的foldLeft and flatMap来做到这一点:

val l : List[Future[UpdateWriteResult]] = ...
println(l.size) // give me 10
l
.foldLeft(Future.successful(UpdateWriteResult(ok = false, -1, -1, Seq(), Seq(), None, None, None))) { 
     case (cur, next) => cur.flatMap(_ => next)
  }

但是文档永远不会像例外一样更新:相反,如果要有一个包含10个样本列表的文档,我会得到1个样本的列表。所以读取比写入更快(我的印象)并且使用foldLeft / flatMap的组合似乎不等待当前未来的完成,所以我如何正确地解决这个问题(没有Await)?< / p>

更新

val futureCollection = DB.getCollection("foo")
val mongoIO = MongoIO(futureCollection)
val id = 1
val samples = List(1.1, 2.2, 3.3)
val l : List[Future[UpdateWriteResult]] = samples.map(sample => mongoIO.updateRecord(id, sample))

2 个答案:

答案 0 :(得分:2)

您必须在foldLeft上执行samples

(mongoIO.updateRecord(id, samples.head) /: samples.tail) {(acc, next) =>
  acc.flatMap(_ => mongoIO.updateRecord(id, next))
}

updateRecord是触发未来的因素,因此您必须确保不要将其称为,直到上一个完成为止。

答案 1 :(得分:1)

我冒昧地对你的原始资料进行了一些小修改:

case class MongoIO(futureCollection : Future[JSONCollection]) {

  def readRecord(id : Int) : Future[Option[Record]] = 
    futureCollection.flatMap(_.find(Json.obj("id" -> id)).one[Record])

  def updateRecord(id : Int, newSample : Double) : Future[UpdateWriteResult] =
    readRecord(id) flatMap {
      case None => Future.successful(UpdateWriteResult(ok = false, -1, -1, Nil, Nil, None, None, None))
      case Some(record) =>
        val newRecord = record.copy(samples = record.samples :+ newSample)
        futureCollection.flatMap(_.update(Json.obj("id" -> id), newRecord))
    }
}

然后我们只需编写序列化/顺序更新:

def update(samples: Seq[Double], id: Int): Future[Unit] = s match {
  case sample +: remainingSamples => updateRecord(id, sample).flatMap(_ => update(remainingSamples, id))
  case _ => Future.successful(())
}