我在Mongodb中有以下文档:
{ "index_column" : "site_id", "mapped_column":"site_name"}
我使用scala代码中的mongo-scala-driver来查询服务器。如何将mapped_column转换为scala String变量?我尝试使用以下代码:
val result = mongocollection.find(equal("index_column", data)).first()
返回org.mongodb.scala.ObservableImplicits$BoxedObservable@207c9b87
是否可以将Observable转换为Iterator?我只需要scala String变量中的mapped_column值。
答案 0 :(得分:0)
我通过将驱动程序切换到mongodb casbah解决了这个问题,可以使用以下代码完成:
{{1}}
答案 1 :(得分:0)
Scala驱动程序是完全异步的,因此您可以订阅结果。最简单的方法是使用foreach:
val result = mongocollection.find(equal("index_column", data)).first()
result.foreach { value => ... }
另一种选择是将Observable
转换为Future
:
Await.result(result.toFuture(), 3 seconds)
答案 2 :(得分:0)
这是一个可能的解决方案。创建一个新的ObserverIterator实例,并使用它订阅一个可观察对象,然后将其用作Iterator。
import org.mongodb.scala.{Observer, Subscription}
import scala.collection.mutable
import scala.concurrent.{Await, Promise}
import scala.concurrent.duration.Duration
import scala.util.Try
import scala.annotation.tailrec
import scala.concurrent.duration._
/**
* An observer that can be used as an Iterator.
* Attention: hasNext and next() are potentially blocking in case the buffer is empty
*
* @param batchSize Number of records to fetch in one batch
* @param timeout Max duration to wait for the queue to fill up or to get an onComplete signal
* @param period Duration to wait before checking if the queue is still empty or if an onComplete signal has been received
* @param threshold Min amount of entries in the buffer below which a new batch should be queried
* @tparam T
*/
class ObserverIterator[T](batchSize: Long = 500,
timeout: Duration = 15.seconds,
period: Duration = 100.millis,
threshold: Long = 100)
extends Observer[T]
with Iterator[T] {
assert(threshold > 0)
assert(batchSize > threshold)
private val buffer = new mutable.Queue[T]()
private var subscription: Option[Subscription] = None
private var requestable = false
override def onSubscribe(subscription: Subscription): Unit = {
this.subscription = Some(subscription)
subscription.request(batchSize)
}
override def onNext(t: T): Unit = {
buffer.enqueue(t)
if (buffer.size >= threshold)
requestable = true
}
private val p = Promise[Unit]()
private val f = p.future
override def onComplete(): Unit = {
p.success(())
requestable = false
}
override def onError(e: Throwable): Unit = throw e
//Blocking
override def hasNext: Boolean = {
if (requestable && buffer.size < threshold) {
subscription.get.request(batchSize)
requestable = false
}
@tailrec
def hasNextImpl(cnt: Duration = timeout): Boolean = {
if (buffer.nonEmpty)
true
else if (p.isCompleted)
false
else {
if (cnt < 0.second)
throw new Exception("hasNext timeout")
else
Try {
Await.result(f, period)
} match {
case _ =>
hasNextImpl(cnt - period)
}
}
}
hasNextImpl()
}
//Blocking
override def next(): T = {
if (hasNext)
buffer.dequeue()
else
throw new Exception("Called next on empty Iterator")
}
}