json - 如何用 JSON 树中的相同键替换所有值

标签 json scala playframework

在 MongoDB 中存储任何 JSON 文档之前,我需要将文档中的所有字符串 id 转换为 BSON id ,反之亦然,当读取任何来自 MongoDB 的文档,我需要将所有 BSON id 转换为字符串 id。也就是说,考虑到以下 JSON...

{
  "id" : "52fe942b790000790079b7d0",
  "email" : "<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0e64616b4e6a61636f6760206d6163" rel="noreferrer noopener nofollow">[email protected]</a>",
  "username" : "joe",
  "subscriptions" : [
    {
      "accountId" : "72fe942b790000790079b755",
      "name" : "test 1",
      "isDefault" : true
    },
    {
      "accountId" : "72fe942b796850790079b743",
      "name" : "test 2",
      "isDefault" : false
    }
  ]
}

...在将其存储到 MongoDB 之前,我需要按照下面的描述对其进行转换...

{
  "_id" : {"$oid" : "52fe942b790000790079b7d0"},
  "email" : "<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fa90959fba9e95979b9394d4999597" rel="noreferrer noopener nofollow">[email protected]</a>",
  "username" : "joe",
  "subscriptions" : [
    {
      "accountId" : {"$oid" : "72fe942b790000790079b755"},
      "name" : "test 1",
      "isDefault" : true
    },
    {
      "accountId" : {"$oid" : "72fe942b796850790079b743"},
      "name" : "test 2",
      "isDefault" : false
    }
  ]
}

...当然,当从 MongoDB 读取文档时,我需要将所有 BSON id 转换回字符串 id

下面是我尝试将 BSON id 转换为字符串 id 的代码(使用 JsZipper 库):

def toPublic(json: JsValue, key: String) = json.updateAllKeyNodes {
  case ((__ \ key), value) => (key -> value \ "$oid")
}

鉴于此方法不会将 id 转换为 _id,因此它根本不起作用,并且始终返回 res0: play.api.libs.json .JsValue = {"accounts":null};另一方面,如果我像这样对 key 进行硬编码......

def toPublic(json: JsValue) = json.updateAllKeyNodes {
  case ((__ \ "accountId"), value) => ("accountId" -> value \ "$oid")
}

...它按预期工作,我在第二个示例中返回了 JSON。我有点迷失了,所以任何帮助将非常感激。

最佳答案

此答案假设您正在使用 play-json-zipper根据this question .

考虑到数据中的不一致(id -> _id 等),我认为如果不进行硬编码,处理这个问题并不容易:

这是一个开始,它处理您以 to/from 方式给出的案例:

def toPublic(json: JsValue) = json.updateAllKeyNodes {
  case ((_ \ "_id"), value) => "id" -> value \ "$oid"
  case ((_ \ "accountId"), value) => "accountId" -> value \ "$oid"
}

def fromPublic(json: JsValue) = json.updateAllKeyNodes {
  case ((_ \ "id"), JsString(value)) => "_id" -> Json.obj("$oid" -> value)
  case ((_ \ "accountId"), JsString(value)) => "accountId" -> Json.obj("$oid" -> value)
}

您可能可以对此进行一些抽象,以更好地处理您的特殊情况。例如,您可以将其与 to/from 关键规则相乘作为映射:

def fromPublicWithKeys(json: JsValue, keys: Map[String,String]): JsValue = {
  def fromPublic(json: JsValue, keys: (String,String)) = json.updateAllKeyNodes {
    case ((_ \ key), JsString(value)) if key == keys._1 => keys._2 -> Json.obj("$oid" -> value)
  }
  keys.foldLeft(json)(fromPublic)
}

用法:

fromPublicWithKeys(stdJson, Map("id" -> "_id", "accountId" -> "accountId"))
// play.api.libs.json.JsValue = {"_id":{"$oid":"52fe942b790000790079b7d0"},"email":"<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="90fafff5d0f4fffdf1f9febef3fffd" rel="noreferrer noopener nofollow">[email protected]</a>","username":"joe","subscriptions":[{"accountId":{"$oid":"72fe942b790000790079b755"},"name":"test 1","isDefault":true},{"accountId":{"$oid":"72fe942b796850790079b743"},"name":"test 2","isDefault":false}]}

注意:您的第一个示例不起作用的一个原因是您尝试对 key 值进行模式匹配,但它创建了一个名为 key 新的隐藏变量绑定(bind)code> (这是我在 Scala 中经常做错的事情。)相反,您需要使用模式匹配 guard,例如 case ((__\path), _)如果路径==键=>...

关于json - 如何用 JSON 树中的相同键替换所有值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21801071/

相关文章:

java - 使用 jackson 序列化通用 JSON

c# - 如何从 web api Controller 返回文件?

java - 使用 AWS Java DynamoDB 流 Kinesis 适配器处理 DynamoDB 流

用于将 Int 限制为范围的 Scala 类型

java - 如何停止在 Play Framework 中多次运行单例类

java - 有没有办法在 Play! 中即时更改 Oracle 连接?框架?

php - Nestable List 插件 PHP MYSQL L Json 树结构

python - Flask JSON 请求为 None

scala - 将单个参数转换为具有无形泛型的 HList

playframework - routesImport 在 playframework 中不起作用