/ / Ersetzen aller Werte durch denselben Schlüssel in einem JSON-Baum - json, scala, playframework

Wie werden alle Werte durch denselben Schlüssel in einem JSON-Baum ersetzt - Json, Scala, Playframework

Vor dem Speichern eines JSON-Dokuments in MongoDB muss die gesamte Zeichenfolge transformiert werden ids im Dokument in BSON ids und umgekehrt, wenn ich ein Dokument aus MongoDB lese, muss ich den gesamten BSON transformieren ids in Zeichenfolge id. Das heißt, angesichts der folgenden JSON ...

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

... Ich muss es wie hier unten beschrieben transformieren, bevor ich es in MongoDB speichere ...

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

... und natürlich muss ich alle BSON zurück konvertieren ids in Zeichenfolge ids beim Lesen des Dokuments aus MongoDB.

Hier unten ist der Code, den ich versucht habe, BSON zu konvertieren ids in Zeichenfolge ids (mit der Taste JsZipper Bibliothek):

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

Vorausgesetzt, dass diese Methode nicht transformiert id in _idfunktioniert es überhaupt nicht und kehrt immer zurück res0: play.api.libs.json.JsValue = {"accounts":null}; auf der anderen Seite, wenn ich den Schlüssel wie folgt fest codiere ...

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

... es funktioniert wie erwartet und ich erhalte im zweiten Beispiel den JSON zurück. Ich bin ein bisschen verloren, also wäre jede Hilfe sehr dankbar.

Antworten:

4 für die Antwort № 1

Diese Antwort setzt voraus, dass Sie verwenden Play-Json-Reißverschluss nach diese Frage.

Angesichts der Inkonsistenzen (id -> _id, etc) in Ihren Daten denke ich nicht, dass es einfach sein wird, dies ohne einige Hardcodierung zu handhaben:

Hier ist ein Anfang, der den Fall behandelt, den Sie in einer von / zu-Weise gegeben haben:

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

Sie können dies wahrscheinlich ein wenig abstrahieren, um Ihre Sonderfälle besser zu handhaben. Zum Beispiel könnten Sie es multiplizieren mit den to / from-Schlüsselregeln als 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)
}

Verwendung:

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

Hinweis: Ein Grund, warum Ihr erstes Beispiel nicht funktioniert, ist, dass Sie versuchen, das Muster mit dem zu vergleichen key value, aber es wird stattdessen eine neue schattierte Variablenbindung erstellt, die aufgerufen wird key (etwas, das ich häufig in Scala falsch machen.) Stattdessen müssen Sie eine Musterübereinstimmung verwenden bewachen, mögen case ((__ path), _) if path == key => ....