关于 ReactiveMongo 的误解错误

Misunderstanding error about ReactiveMongo

我定义了以下要建模的 class :

case class Record(
                     recordKey: String,
                     channels: Map[String, Channel],
                     )

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

现在,我想像这样(在另一个 class 中)从反应式 mongo 中获取一个这种类型的对象:

import scala.concurrent.duration._
import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import reactivemongo.api._
import reactivemongo.api.collections.bson.BSONCollection
import reactivemongo.bson.BSONDocument

object Test {
  val collection = connect()
  val timeout = 10.seconds
  def connect() : BSONCollection = {
    val config = ConfigFactory.load()
    val driver = new MongoDriver
    val connection = driver.connection(List(config.getString("mongodb.uri")))
    val db = connection("/toto")
    db.collection("foo")
  }

  def findRecord(recordKey : String) : Record = {
    return Test.collection
      .find(BSONDocument("recordKey"->recordKey))
      .one[Record]
  }

但是这段代码无法编译:

 could not find implicit value for parameter reader: reactivemongo.bson.BSONDocumentReader[Record]

有人可以解释一下如何解决这个问题吗?

我也测试过:

def findRecord(recordKey : String) : Record = {
    val futureRecord : Future[Option[Record]] =
      Test.collection
        .find(BSONDocument("recordKey"->recordKey))
        .one[Record]
    return Await.result(futureRecord, 10.seconds).getOrElse(null)
  }

我也添加了我的 build.sbt :

libraryDependencies ++= Seq(
  "org.apache.spark" % "spark-streaming_2.10" % "1.5.2",
  "org.apache.spark" % "spark-streaming-kafka_2.10" % "1.5.2",
  "org.slf4j" % "slf4j-api" % "1.7.13",
  "org.slf4j" % "slf4j-simple" % "1.7.13",
  "com.amazonaws" % "aws-java-sdk" % "1.10.12",
  "com.typesafe.play" % "play-json_2.10" % "2.4.6",
  "com.typesafe" % "config" % "1.3.0",
  "org.scalaj" %% "scalaj-http" % "2.2.1",
  "com.typesafe.akka" % "akka-actor_2.10" % "2.3.14",
  "org.reactivemongo" %% "reactivemongo" % "0.11.9",
  "com.github.nscala-time" %% "nscala-time" % "2.6.0"
)

请注意,它不是 Play App

您需要为您的案例定义一个 BSONDocumentReader class Record。这里有一个link到Documentation。非常类似于 Play JSON Readers and Writers Reactive Mongo 需要了解如何在域对象和 BSONDocument 之间来回转换。与 Play JSON 类似,您也可以以更手动的方式编写这些内容(编写一个 BSONDocumentReader 实例和一个 BSONDocumentWriter 实例)并自定义每个细节并应用转换等。风格相似to Play JSON's format 你在上面使用的 ReactiveMongo 确实提供了有用的宏来为你生成这些 classes。

为了您的记录 class,您需要向您的对象添加这样的隐式 val:

import reactivemongo.bson._

implicit val recordHandler: BSONHandler[BSONDocument, Record] = Macros.handler[Record]

/* Or only one of these [if your only ever writing or reading this data etc:
 implicit val recordReader: BSONDocumentReader[Record] = Macros.reader[Record]
 implicit val recordWriter: BSONDocumentWriter[Record] = Macros.writer[Record]
*/

我会说尝试从宏开始,看看它们是否满足您的需求。如果您需要对 processing/transformation 进行更多控制,您可以定义自己的 BSONDocumentReaderBSONDocumentWriter 实例。

更新记录 class

import play.api.libs.json.Json
import reactivemongo.bson._


case class Channel(label: String,amplitude: Double,position: Option[String])

object Channel {
  implicit val ChannelFormat = Json.format[Channel]
  implicit val channelHandler: BSONHandler[BSONDocument, Channel] =   Macros.handler[Channel]
 }

object RecordType extends Enumeration {
 type RecordType = Value
 val T1 = Value
 implicit val enumFormat = new Format[RecordType] {
  def reads(json: JsValue) = JsSuccess(RecordType.withName(json.as[String]))
  def writes(enum: RecordType) = JsString(enum.toString)
 }
 implicit  object RecordTypeReader extends BSONDocumentReader[RecordType] {
  def read(doc: BSONDocument) : RecordType  = {
     RecordType.withName(doc.getAs[String]("recordType").get)
  }
}
implicit object RecordTypeWriter extends BSONDocumentWriter[RecordType] {
  def write(recordType: RecordType) : BSONDocument = BSONDocument(
    "recordType" -> BSONString(recordType.toString)
  )
 }
}

case class Record(recordKey: String,recordType: RecordType.Value,channels: Map[String, Channel])

object Record {
 implicit val RecordFormat = Json.format[Record]
 implicit val recordHandler: BSONHandler[BSONDocument, Record] =  Macros.handler[Record]
}