如何用JSON树中的相同键替换所有值 [英] How to replace all the values with the same key in a JSON tree

查看:106
本文介绍了如何用JSON树中的相同键替换所有值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在将任何JSON文档存储在MongoDB中之前,我需要将文档中的所有字符串id转换为BSON id,反之亦然,当从MongoDB中读取任何文档时,我需要转换所有BSON id转换为字符串id.就是说,鉴于以下JSON ...

Before storing any JSON document in MongoDB, I need to transform all the string ids in the document into BSON ids and, vice-versa, when reading any document from MongoDB, I need to transform all the BSON ids into string id. That said, 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
    }
  ]
}

...在将其存储在MongoDB中之前,我需要按如下所述对其进行转换...

... I need to transform it as described here below before storing it in MongoDB...

{
  "_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
    }
  ]
}

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

... and of course I need to convert back all the BSON ids into string ids when reading the document from MongoDB.

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

Here below is the code I've tried to convert BSON ids into string ids (using the JsZipper library):

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

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

Given that this method does not transform id into _id, it doesn't work at all and always returns res0: play.api.libs.json.JsValue = {"accounts":null}; on the other hand, if I hardcode the key like this...

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

...它按预期方式工作,在第二个示例中,我取回了JSON.我有点迷茫,所以我们将不胜感激.

... it works as expected and I get back the JSON in the second example. I'm a bit lost, so any help would be really appreciated.

推荐答案

此答案假定您正在使用此问题中的"play-json-zipper" .

This answer assumes you're using play-json-zipper as per this question.

鉴于您数据中的不一致(id-> _id等),我认为没有一些硬编码就很难解决这个问题:

Given the inconsistencies (id -> _id, etc) in your data I don't think it's going to be easy to handle this without some hard-coding:

这是一个开始,它以往返方式处理您提出的情况:

Here's a start, which handles the case you've given in a to/from manner:

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关键规则相乘,以作图:

You can probably abstract this a fair bit to handle your special cases more nicely. For instance you could apply it multiply with the to/from key rules as a map:

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":"joe@domain.com","username":"joe","subscriptions":[{"accountId":{"$oid":"72fe942b790000790079b755"},"name":"test 1","isDefault":true},{"accountId":{"$oid":"72fe942b796850790079b743"},"name":"test 2","isDefault":false}]}

注意:第一个示例不起作用的一个原因是,您试图对key值进行模式匹配,但是它创建了一个新的带阴影的变量绑定,称为key(我经常这样在Scala中做错了.)相反,您需要使用模式匹配 guard ,例如case ((__ \ path), _) if path == key => ....

Note: one reason your first example doesn't work is that you're trying to pattern match the key value, but it's instead creating a new shadowed variable binding called key (something I often do wrong in Scala.) Instead you need to use a pattern match guard, like case ((__ \ path), _) if path == key => ....

这篇关于如何用JSON树中的相同键替换所有值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆