reactivemongo-demo-app icon indicating copy to clipboard operation
reactivemongo-demo-app copied to clipboard

Problem with nested custom objects

Open shenghuang opened this issue 11 years ago • 0 comments

Good afternoon Stéphane,

I am following your examples and they are great. However, I cannot make nested object works with 0.8.

I'm trying to store a nested document in MongoDB through Scala. The document looks like: 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) }

Basically I want to store nested descriptions, which could be of multiple languages in the Project document.

The code I wrote is:

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:*) } } }

Scala doesn't like the line "description" -> BSONArray(project.description)

However, the following alternative, which is similar to your examples, works although I cannot use a List/Array to allow more than two languages:

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.getAsBSONObjectID, document.getAsBSONString.map(_.value).get, LocaleTextBSONReader.fromBSON(document.getAsBSONDocument.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) } }

I appreciate if you can shed some light on my problem. Thank you very much for your help.

shenghuang avatar Dec 06 '13 21:12 shenghuang