Search code examples
scalaplay-json

create custom JsObject out of case class


im getting in my api some case class that looks like this:

case class UserUpdate(
  name: Option[String], 
  age: Option[String], 
  city: Option[String])

from this case class I need to build update json for mongo that looks like:

{"basicInfo.name": "new nameeee","age.vatId": "23"}

since all the fields are optional, I need to go over the fields and build it by the ones that are defined.

so I did something like this:

val updateAsMap = Json.toJson(userUpdateObj).as[JsObject]
  .fields.map(fieldTpl => fieldTpl.copy(_1 =  s"basicInfo.${fieldTpl._1}")).toMap
val userUpdateJson = Json.toJson(updateAsMap)
val query = json("userId" -> userId)
val update = json("$set" -> userUpdateJson)

is there a better suggestion, something that will look more elegant?


Solution

  • One option could be to convert UserUpdate to an intermediary case class, say MongoModel, and then convert MongoModel to JSON. For example,

    import play.api.libs.json._
    
    case class MongoModel(
      `basicInfo.name`: Option[String] = None,
      `age.vatId`: Option[String] = None
    )
    
    object MongoModel {
      implicit val codec = Json.format[MongoModel]
    }
    
    case class UserUpdate(
        name: Option[String] = None, 
        age: Option[String] = None, 
        city: Option[String] = None
    ) {
      def toMongoModel = 
        MongoModel(
          `basicInfo.name` = name,
          `age.vatId` = age
        )
    }
    
    val userUpdate = UserUpdate(name = Some("new nameeee"), age = Some("23"))
    
    Json.toJson(userUpdate.toMongoModel) // {"basicInfo.name": "new nameeee", "age.vatId": "23"}: JsValue
    

    Note the usage of backticks in MongoModel.