Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with nested custom objects #7

Open
shenghuang opened this issue Dec 6, 2013 · 0 comments
Open

Problem with nested custom objects #7

shenghuang opened this issue Dec 6, 2013 · 0 comments

Comments

@shenghuang
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant