1

Scala を使用して、ネストされたドキュメントを MongoDB に保存しようとしています。ドキュメントは次のようになります。

Project {
    "_id": ObjectId("528547370cf6e41449003512"),
    "highLevelCode": NumberLong(3),
    "description": [
        {"_id": ObjectId("528547370cf6e41449003521"),
        "lang": "en",
        "desc": "desc in English"}, 
        {"_id ": ObjectId("528547370cf6e41449003522"), 
        "lang": "fr", 
        "desc": "desc en francais"}],
    "budget": NumberLong(12345)
}

基本的に、ネストされた説明を保存したいと考えています。これは、プロジェクト ドキュメント内の複数の言語である可能性があります。

私が書いたコードは次のとおりです。

import reactivemongo.bson._
import reactivemongo.bson.handlers.{BSONWriter, BSONReader}
import reactivemongo.bson.BSONLong
import reactivemongo.bson.BSONString

case class LocaleText(
  id: Option[BSONObjectID],
  lang: String,
  textDesc: String
)

object LocaleText {
  implicit object LocaleTextBSONReader extends BSONReader[LocaleText] {
    def fromBSON(document: BSONDocument): LocaleText = {
      val doc = document.toTraversable

      LocaleText(
        doc.getAs[BSONObjectID]("_id"),
        doc.getAs[BSONString]("lang").map(_.value).get,
        doc.getAs[BSONString]("textDesc").map(_.value).get
      )
    }
  }

  implicit object LocaleTextBSONWriter extends BSONWriter[LocaleText] {
    def toBSON(localText: LocaleText) = {
      BSONDocument(
        "_id" -> localText.id.getOrElse(BSONObjectID.generate),
        "lang" -> BSONString(localText.lang),
        "textDesc" -> BSONString(localText.textDesc)
      )
    }
  }    
}

case class Project(
  id:                Option[BSONObjectID],
  description:          List[LocaleText],
  budget:               Option[Long]
  )

object Project {

  implicit object ProjectReader extends BSONReader[Project]{
    def fromBSON(doc: BSONDocument): Project = {
      val document = doc.toTraversable

      Project(
        document.getAs[BSONObjectID]("_id"),
        document.getAs[BSONArray]("description").map { values =>
            values.values.toList.flatMap { case value =>
              value match {
                case v: LocaleText => Some(v.asInstanceOf[LocaleText])
                case _ => None
              }
            }
        }.getOrElse(List.empty),
        document.getAs[BSONLong]("budget").map(_.value)
      )
    }
  }

  implicit object ProjectWriter extends BSONWriter[Project]{
    def toBSON(project: Project): BSONDocument = {
      BSONDocument(
        "_id"                   -> project.id.getOrElse(BSONObjectID.generate),
    "description"           -> BSONArray(project.description)
      ).append(Seq(
        project.budget.map(b => "budget" -> BSONLong(b))
      ).flatten:_*)
    }
  }
}

ただし、次のようなコンパイルエラーが発生しました

オーバーロードされたメソッド値は、代替手段で適用されます: [エラー] (プロデューサー: reactmongo.bson.Implicits.Producer[(String, reactmongo.bson.BSONValue)],プロデューサー: reactmongo.bson.Implicits.Producer[(String, reactmongo.bson.BSONValue) )] )reactivemongo.bson.AppendableBSONDocument [エラー] (els: (文字列、reactivemongo.bson.BSONValue) )reactivemongo.bson.AppendableBSONDocument [エラー] を適用できません ((文字列、reactivemongo.bson.BSONObjectID)、List[LocaleText ])...

基本的に、Scala は "description" という行が好きではありません -> BSONArray(project.description)

ただし、リスト/配列を使用して2つ以上の言語を許可することはできませんが、次の代替手段が機能します。

case class LocaleText(
  enDesc: String,
  frDesc: String)

case class Project(
  id:                   Option[BSONObjectID],
  description:          LocaleText)

object Project {
implicit object LocaleTextBSONReader extends BSONReader[LocaleText] {
    def fromBSON(document: BSONDocument): LocaleText = {
      val doc = document.toTraversable

      LocaleText(
        doc.getAs[BSONString]("enDesc").map(_.value).get,
        doc.getAs[BSONString]("frDesc").map(_.value).get
      )
    }
  }

  implicit object LocaleTextBSONWriter extends BSONWriter[LocaleText] {
    def toBSON(localText: LocaleText) = {
      BSONDocument(
        "enDesc" -> BSONString(localText.enDesc),
        "frDesc" -> BSONString(localText.frDesc)
      )
    }
  }    

implicit object ProjectReader extends BSONReader[Project]{
def fromBSON(doc: BSONDocument): Project = {
  val document = doc.toTraversable

  Project(
    document.getAs[BSONObjectID]("_id"),
    document.getAs[BSONString]("iatiId").map(_.value).get,
    LocaleTextBSONReader.fromBSON(document.getAs[BSONDocument]("description").get)
  }
}

implicit object ProjectWriter extends BSONWriter[Project]{
def toBSON(project: Project): BSONDocument = {
  BSONDocument(
    "_id"                   -> project.id.getOrElse(BSONObjectID.generate),
    "iatiId"                -> BSONString(project.iatiId),
    "description"           -> LocaleTextBSONWriter.toBSON(project.description) 
 }
}

Project.description を Mongo 用の LocaleText のリストである BSONArray に変換するにはどうすればよいですか? 私の問題に光を当てていただければ幸いです。ご助力ありがとうございます。

4

2 に答える 2

3

最後に、私は自分の質問に対する解決策を見つけました。これが ReactiveMongo 0.8 に苦労している他の人にも役立つことを願っています:

case class LocaleText(
    lang: String,
    desc: String)

case class Project(
    id:                 Option[BSONObjectID],
    descriptions:         List[LocaleText])

object Project {
  implicit object LocaleTextBSONReader extends BSONReader[LocaleText] {
        def fromBSON(document: BSONDocument): LocaleText = {
          val doc = document.toTraversable

          LocaleText(
            doc.getAs[BSONString]("lang").get.value,
            doc.getAs[BSONString]("desc").get.value
          )
        }
      }

      implicit object LocaleTextBSONWriter extends BSONWriter[LocaleText] {
        def toBSON(localText: LocaleText) = {
          BSONDocument(
            "lang" -> BSONString(localText.lang),
            "desc" -> BSONString(localText.desc)
          )
        }
      }    

  implicit object ProjectReader extends BSONReader[Project]{
    def fromBSON(doc: BSONDocument): Project = {
      val document = doc.toTraversable

      Project(
        document.getAs[BSONObjectID]("_id"),
        document.getAs[BSONArray]("descriptions").get.toTraversable.toList.map { descText =>
            LocaleTextBSONReader.fromBSON(descText.asInstanceOf[TraversableBSONDocument]
        }
      )
    }
  }

  implicit object ProjectWriter extends BSONWriter[Project]{
    def toBSON(project: Project): BSONDocument = {
      BSONDocument(
        "_id"                   -> project.id.getOrElse(BSONObjectID.generate),
        "descriptions"          -> BSONArray(project.descriptions.map {
        description => LocaleTextBSONWriter.toBSON(description)
      }: _*)
    }
  }
于 2013-12-23T21:35:30.483 に答える