Reputation: 7735
My stack is: Scala 2.11.6, ReaciveMongo 0.11.6, Play 2.4.2, Mongo 3.0.4
I have a list of queries to mongo, which I need to perform conditionally one after another (If number of results is less then MAX possible).
As a solution I'm doing following:
possibleQueries.
// find returns Enumerator[JsObject]
map(query => searchableCollection.find(query)).
// combine Enumerators with andThen
foldLeft(Enumerator.empty[JsObject])({ (e1, e2) => e1.andThen(e2) }) through
// Take only specified amount of suggestions
take[JsObject](MAX_AMOUNT)
The problem with this, is that it eagerly searches for data with searchableCollection.find(query) (maybe I'm wrong), and might not even fetch returned results, if previous query returns MAX_AMOUNT of results.
How to rewrite this, so that search would be called only if previous Enumeration has not filled MAX_AMOUNT of responses?
UPDATE
The solution I went with is
implicit class EnumeratorExtension[E](parent: Enumerator[E]) {
/**
* Create an Enumeratee that combines parent & e if parent was empty.
*/
def andIfEmpty(e: => Enumerator[E]): Enumerator[E] = new Enumerator[E] {
def apply[A](i: Iteratee[E, A]): Future[Iteratee[E, A]] = {
var empty = true
parent.
map(e => {
empty = false
e
})(defaultExecutionContext).
apply(i).
flatMap(r => {
if (empty)
e.apply(r)
else
Future.successful(r)
})(defaultExecutionContext)
}
}
}
Upvotes: 1
Views: 99
Reputation: 2824
How about wrap the search and make it lazy?
class LazyEnumerator[E](e: => Enumerator[E]) extends Enumerator[E] {
lazy _e = e
def apply[A](i: Iteratee[E, A]) = _e.apply(i)
}
possibleQueries.
map(query => new LazyEnumerator(searchableCollection.find(query))).
foldLeft(Enumerator.empty[JsObject])({ (e1, e2) => e1.andThen(e2) }) through
take[JsObject](MAX_AMOUNT)
Upvotes: 1