0

I have Play 2.3 appliction with reactive mongo plugin. I have base document:

trait TemporalDocument {
  val created: Option[DateTime] = Some(new DateTime())
  val updated: Option[DateTime] = Some(new DateTime())
}

and one of the concrete document:

case class User(name: String) extends TemporalDocument

object User{
  implicit val userFormat = Json.format[User]
}

So when I persist it to mongo db using reactive mongo plugin only name is persisted, created/updated fields are not.

My repository looks like:

trait MongoDocumentRepository[T <: TemporalDocument] extends ContextHolder {

  private val db = ReactiveMongoPlugin.db

  def insert(document: T)(implicit writer: Writes[T]): Future[String] = {
    collection.insert(document).map {
      lastError => lastError.toString
    } recover {
      case e: Exception => sys.error(e.getMessage)
    }
  }

  private def collection: JSONCollection = db.collection[JSONCollection](collectionName)

  implicit object BSONDateTimeHandler extends BSONHandler[BSONDateTime, DateTime] {
    def read(time: BSONDateTime) = new DateTime(time.value)

    def write(jdtime: DateTime) = BSONDateTime(jdtime.getMillis)
  }
}

Problem is that I will have many documents extended from base document and I do not want each time init those dates and probably some other fields. Is it possible to do something like this?

janis.kom
  • 38
  • 8

1 Answers1

2

Firstly, we can halve the surface-area of the problem; Reactive Mongo and/or the Play Reactive Mongo Plugin are not relevant here, it's Play's JSON macros that build the appropriate JSON structures (or not, in this case) that are responsible.

If I set up a TemporalDocument and User as in your code, and then write it out:

val user = User("timmy")

println(Json.toJson(user))

I get:

{"name":"timmy"}

I haven't looked into it, but I suspect this is because the created and updated fields don't appear in the "field list" of the User case class.

If I rework your code a little bit like this:

trait TemporalDocument {
  val created: Option[DateTime]
  val updated: Option[DateTime]
}

case class User(
                name: String,
                val created: Option[DateTime] = Some(new DateTime()),
                val updated: Option[DateTime] = Some(new DateTime())) 
                extends TemporalDocument

Then the same test code gets the desired behaviour from play-json:

{"name":"timmy","created":1410930805042,"updated":1410930805071}
millhouse
  • 9,817
  • 4
  • 32
  • 40
  • You don't even need `val`s in `User` constructor because case class constructor parameters are public `val`s by default – yahor Jun 08 '16 at 01:36