Сопоставление класса case с документом mongodb с использованием реактивного монго

Ниже мой простой документ, представляющий ссылку. Для этого я использую реактивный монго в scala.

Я получаю эту ошибку во время компиляции:

app/components/Link.scala:60:11: Не найден десериализатор Json для компонентов типа. Ссылка. Попробуйте реализовать неявное чтение или формат для этого типа. [ошибка] .one[ссылка]) [ошибка] ^ [ошибка] найдена одна ошибка

Я создал имплициты в своем объекте-компаньоне Link, который также импортировал в свой класс LinkRepo.

Правильно ли я обрабатываю документ mongo _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")

person Blankman    schedule 03.01.2019    source источник
comment
Вы используете коллекцию JSON, но предоставленная коллекция — BSON, поэтому вам нужно убедиться, что конверсии из ImplicitBSONHandlers импортируются из reactivemongo.play.json.   -  person cchantep    schedule 03.01.2019
comment
Я добавил и import reactivemongo.play.json.ImplicitBSONHandlers, и import reactivemongo.play.json._, но все равно получаю ту же ошибку.   -  person Blankman    schedule 03.01.2019
comment
Проверьте версии   -  person cchantep    schedule 03.01.2019
comment
@cchantep Я добавил свои версии к моему вопросу. Я использую реактивмонго 0.16.0-play26.   -  person Blankman    schedule 04.01.2019


Ответы (1)


Насколько я знаю, вам НЕ НУЖНО использовать BSONObjectID, но это рекомендуется. Но вы должны использовать поле «_id» в монго, иначе поведение по умолчанию будет заключаться в создании _id в вашем документе при создании нового... так что ваш документ будет иметь _id и id.

Таким образом, вы должны получить идентификатор из «_id» и записать его в «_id», даже если ваш класс case имеет идентификатор.

Что касается обработчиков, для базовых классов случаев вы можете использовать предоставленные ими макросы:

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

это создаст Reader и Writer для вашей ссылки.

При использовании макросов у вас есть аннотации, которые вы можете использовать, чтобы выделить свой идентификатор, который будет «_id» в монго:

import reactivemongo.bson.Macros.Annotations.Key

case class Link(
  @Key("_id")
  id: Link.ID,
  name: String,
  url: String
)
person FerranJr    schedule 03.01.2019
comment
Но поскольку в этом случае у меня есть собственный обработчик, почему он не находит неявное? - person Blankman; 03.01.2019
comment
Я понимаю, что вы используете JSONCollection.. это специфично для Play... который, я думаю, преобразует BSON в JSON, поэтому вы не предоставляете средства чтения Json для этих документов... но не уверен, поскольку я не использовал reactiveMongo с игрой, Я использую его в akka-http... извините за это - person FerranJr; 03.01.2019