播放 2.4.1:如何替换 JSON 树中出现的一个或多个键的所有位置

Play 2.4.1: How to replace all the occurrences of one or more keys in a JSON tree

鉴于以下 JSON...

{
  "id" : "52fe942b790000790079b7d0",
  "email" : "joe@domain.com",
  "username" : "joe",
  "subscriptions" : [
    {
      "accountId" : "72fe942b790000790079b755",
      "name" : "test 1",
      "isDefault" : true
    },
    {
      "accountId" : "72fe942b796850790079b743",
      "name" : "test 2",
      "isDefault" : false
    }
  ]
}

.. 我需要根据 MongoDB 的要求将每个 id 转换为 ObjectID(即 id -> _id \ $oidaccountId -> 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
    }
  ]
}

玩 2.3.8 我用了 play-json-zipper 并且 updateAllKeyNodes 成功了:

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"
}

不幸的是,对于 play 2.4.1,我必须从我的项目中删除 play-json-zipper,因为它不支持新的 JSON 模型。

使用标准 Play JSON 库获得相同结果的正确替代方法是什么?

您可以将 -+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

对于更复杂的需求:

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