我正在使用play2和reactivemongo从mongodb获取结果。需要转换结果的每个项目以添加一些元数据。之后我需要对它进行一些排序。
为了处理转换步骤,我使用enumerate()
:
def ideasEnumerator = collection.find(query)
.options(QueryOpts(skipN = page))
.sort(Json.obj(sortField -> -1))
.cursor[Idea]
.enumerate()
然后我按如下方式创建一个Iteratee:
val processIdeas: Iteratee[Idea, Unit] =
Iteratee.foreach[Idea] { idea =>
resolveCrossLinks(idea) flatMap { idea =>
addMetaInfo(idea.copy(history = None))
}
}
最后我喂了Iteratee:
ideasEnumerator(processIdeas)
现在我被卡住了。我看到的每个例子都在println
内部有一些foreach
,但似乎并不关心最终结果。
因此,当返回并转换所有文档时,如何获取序列,列表或其他一些我可以进一步处理的数据类型?
答案 0 :(得分:2)
将您的Iteratee的签名从Iteratee[Idea, Unit]
更改为Iteratee[Idea, Seq[A]]
,其中A是类型。基本上,Iteratee的第一个参数是输入类型,第二个参数是输出类型。在您的情况下,您将输出类型指定为单位。
看看下面的代码。它可能无法编译,但它为您提供了基本用法。
ideasEnumerator.run(
Iteratee.fold(List.empty[MyObject]) { (accumulator, next) =>
accumulator + resolveCrossLinks(next) flatMap { next =>
addMetaInfo(next.copy(history = None))
}
}
) // returns Future[List[MyObject]]
如您所见,Iteratee只是一个状态机。只需提取Iteratee部分并将其分配给val:
val iteratee = Iteratee.fold(List.empty[MyObject]) { (accumulator, next) =>
accumulator + resolveCrossLinks(next) flatMap { next =>
addMetaInfo(next.copy(history = None))
}
}
随时随地使用它,您需要将您的想法转换为列表[MyObject]
答案 1 :(得分:0)
在你的答案的帮助下,我最终得到了
val processIdeas: Iteratee[Idea, Future[Vector[Idea]]] =
Iteratee.fold(Future(Vector.empty[Idea])) { (accumulator: Future[Vector[Idea]], next:Idea) =>
resolveCrossLinks(next) flatMap { next =>
addMetaInfo(next.copy(history = None))
} flatMap (ideaWithMeta => accumulator map (acc => acc :+ ideaWithMeta))
}
val ideas = collection.find(query)
.options(QueryOpts(page, perPage))
.sort(Json.obj(sortField -> -1))
.cursor[Idea]
.enumerate(perPage).run(processIdeas)
这稍后需要ideas.flatMap(identity)
来删除未来的未来期货,但我对它很好,我觉得一切看起来都很惯用和优雅。
与创建列表并在之后迭代后获得的性能虽然可以忽略不计。