【问题标题】:Mapping a case class to a mongodb document using reactive mongo使用响应式 mongo 将案例类映射到 mongodb 文档
【发布时间】:2019-01-03 14:41:57
【问题描述】:

下面是代表链接的简单文档。为此,我在 scala 中使用了 reactivemongo。

我在编译期间收到此错误:

app/components/Link.scala:60:11: 找不到类型的 Json 反序列化器 组件。链接。尝试为此实现隐式读取或格式 类型。 [error] .one[Link]) [error] ^ [error] 一个错误 找到了

我在我的 Link 伴随对象中创建了隐式,我也将它导入到我的 LinkRepo 类中。

我是否正确处理了 mongo 文档 _id?
我应该使用字符串映射到文档 ID,对最佳实践感到困惑吗?我是否必须在某些时候将字符串转换为 BSONObjectID?

package components

import javax.inject.Inject
import reactivemongo.bson._

import reactivemongo.api.ReadPreference
import reactivemongo.api.collections.bson.BSONCollection
import reactivemongo.bson.{ BSONDocument, BSONObjectID }
import reactivemongo.api.commands.{ UpdateWriteResult, WriteResult, Upserted }
import reactivemongo.api.commands.bson.BSONUpdateCommand._
import reactivemongo.api.commands.bson.BSONUpdateCommandImplicits._

case class Link(id: Link.ID,
                name: String,
                url: String)


object Link {

  type ID = String

  implicit val linkReader: BSONDocumentReader[Link] =
    BSONDocumentReader[Link] { doc: BSONDocument =>
      Link(
        doc.getAs[String]("id").getOrElse(""),
        doc.getAs[String]("name").getOrElse(""),
        doc.getAs[String]("url").getOrElse(""))
    }

  implicit val linkWriter: BSONDocumentWriter[Link] =
    BSONDocumentWriter[Link] { link: Link =>
      BSONDocument(
        "id" -> link.id,
        "name" -> link.name,
        "url" -> link.url)
    }

}

import scala.concurrent.{ ExecutionContext, Future }
import reactivemongo.bson.{ BSONDocument, BSONObjectID }

import reactivemongo.api.{ Cursor, ReadPreference }
import reactivemongo.api.commands.WriteResult

import reactivemongo.play.json._
import reactivemongo.play.json.collection.JSONCollection

import play.modules.reactivemongo.ReactiveMongoApi

class LinkRepo @Inject()(implicit ec: ExecutionContext, reactiveMongoApi: ReactiveMongoApi) {
  import Link._

  def linksCol: Future[JSONCollection] = reactiveMongoApi.database.map(_.collection("links"))

  def byId(id: Link.ID): Future[Option[Link]] = {
    linksCol.flatMap(_.find(
      selector = BSONDocument("_id" -> id),
      projection = Option.empty[BSONDocument])
      .one[Link])
  }



}

我的 sbt 有这些 lib 版本:

scalaVersion := "2.12.7"

libraryDependencies += guice
libraryDependencies ++= Seq(
  guice,
  "joda-time" % "joda-time" % "2.9.9",
  "net.ruippeixotog" %% "scala-scraper" % "2.1.0",
  "org.reactivemongo"      %% "play2-reactivemongo" % "0.16.0-play26",
  "org.scalatestplus.play" %% "scalatestplus-play" % "3.1.2" % Test
)

插件:

addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.20")

【问题讨论】:

  • 您使用的是 JSON 集合,但提供的集合是 BSON,因此您需要确保来自 ImplicitBSONHandlers 的转换是从 reactivemongo.play.json 导入的。
  • 我同时添加了import reactivemongo.play.json.ImplicitBSONHandlersimport reactivemongo.play.json._,但仍然出现同样的错误。
  • 检查版本
  • @cchantep 我将我的版本添加到我的问题中。我正在使用 reactivemongo 0.16.0-play26。

标签: mongodb scala playframework play-reactivemongo


【解决方案1】:

据我所知,您不需要使用 BSONObjectID,但建议您这样做。 但是您应该在 mongo 中使用“_id”字段,否则默认行为将是在您创建新文档时在文档上创建一个 _id...所以您的文档将具有 _id 和 id。

因此,即使您的案例类是 id,您也应该从“_id”获取 id 并将其写入“_id”。

根据处理程序,对于基本案例类,您可以使用它们提供的宏:

implicit val linkHandler: BSONDocumentHandler[Link] = Macros.handler

这将为您的链接生成 Reader 和 Writer。

使用宏时,您可以使用注释来突出显示您的 id,在 mongo 上将是“_id”:

import reactivemongo.bson.Macros.Annotations.Key

case class Link(
  @Key("_id")
  id: Link.ID,
  name: String,
  url: String
)

【讨论】:

  • 但是既然在这种情况下我有自己的处理程序,为什么它没有找到隐含的?
  • 我意识到您正在使用 JSONCollection .. 这是 Play 特有的...我猜它会将 BSON 转换为 JSON,因此您不会为这些文档提供 Json 阅读器...但我不确定没有在游戏中使用 reactiveMongo,我在 akka-http 中使用它......对此感到抱歉
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-30
  • 1970-01-01
  • 2016-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-13
相关资源
最近更新 更多