[ Play 2.4.1: How to replace all the occurrences of one or more keys in a JSON tree ]
Given the following JSON...
{
"id" : "52fe942b790000790079b7d0",
"email" : "joe@domain.com",
"username" : "joe",
"subscriptions" : [
{
"accountId" : "72fe942b790000790079b755",
"name" : "test 1",
"isDefault" : true
},
{
"accountId" : "72fe942b796850790079b743",
"name" : "test 2",
"isDefault" : false
}
]
}
.. I need to transform each id to an ObjectID as required by MongoDB (i.e. id
-> _id \ $oid
and accountId
-> accountId \ $oid
:
{
"_id" : {"$oid" : "52fe942b790000790079b7d0"},
"email" : "joe@domain.com",
"username" : "joe",
"subscriptions" : [
{
"accountId" : {"$oid" : "72fe942b790000790079b755"},
"name" : "test 1",
"isDefault" : true
},
{
"accountId" : {"$oid" : "72fe942b796850790079b743"},
"name" : "test 2",
"isDefault" : false
}
]
}
Up to Play 2.3.8 I used play-json-zipper
and updateAllKeyNodes
did the trick:
import play.api.libs.json._
import play.api.libs.json.extensions._
json.updateAllKeyNodes {
case ((_ \ "_id"), value) => "id" -> value \ "$oid"
case ((_ \ "accountId"), value) => "accountId" -> value \ "$oid"
}
Unfortunately with play 2.4.1 I have to remove play-json-zipper
from my project because it doesn't support the new JSON model.
What is the correct alternative to achieve the same result with the standard Play JSON library?
Answer 1
You can use -
and +
with JsObject
.
val json = Json.parse("""{"id":"123","a":1}""")
val id = (json \ "id").as[JsString] // find the id
val fixed = json.as[JsObject] - ("id") + ("_id", id) // replace
For the more complicated requirements:
Json.parse(str) match
case JsObject(j) =>
val newId = JsObject(Seq("$old" -> j("id")))
val newSs = j("subscriptions") match {
case JsArray(ss) => JsArray(ss.map {
case JsObject(s) =>
val i = s("accountId").as[JsString]
val n = JsObject(Seq("$old" -> i))
JsObject(s + ("accountId" -> n))
})
}
JsObject(j - "id" + ("_id" -> newId) + ("subscriptions" -> newSs))
}