Again and again I am struggling when a function relies on some future results. This usually boils down to a result like Future[Seq[Future[MyObject]]]
To get rid of that
Two handy functions on the Future companion object you should know could help here, the first, and easier to wrap your head around is Future.sequence. It takes a sequnce of futures and returns a Future of a sequence. If are ending up with a Future[Seq[Future[MyObject]]], lets call that result. then you can change this to a Future[Future[Seq[MyObject]]] with result.map(Future.sequence(_))
Then to collapse a Future[Future[X]] for any X, you can run "result.flatMap(identity)", in fact, you can do this for any M[M[X]] to create a M[X] as long as M has flatMap.
Another useful function here is Future.traverse. It is basically the result of taking a Seq[A], mapping it to a Seq[Future[B]], then running Future.sequence to get a Future[Seq[B]] So in your example, you'd have:
ideas.map{ Future.traverse(_){ idea =>
/*something that returns a Future[JsObject]*/
} }.flatMap(identity)
However, many times when you are running flatMap(identity), you could be turning a map into a flatMap, and this is the case here:
ideas.flatMap{ Future.traverse(_) { idea =>
/*something that returns a Future[JsOjbect]*/
} }