[英]Play framework (Scala) - Getting subset of json that contains arrays
I have many very large json-objects that I return from Play Framework with Scala. 我有很多非常大的json对象,它们是从Scala的Play Framework返回的。
In most cases the user doesn't need all the data in the objects, only a few fields. 在大多数情况下,用户不需要对象中的所有数据,仅需要几个字段。 So I want to pass in the paths I need (as query parameters), and return a subset of the json object.
所以我想传递我需要的路径(作为查询参数),并返回json对象的子集。
I have looked at using JSON Transformers for this task. 我已经考虑过使用JSON Transformers来完成此任务。
Filter code 筛选代码
def filterByPaths(paths: List[JsPath], inputObject: JsObject) : JsObject = {
paths
.map(_.json.pick)
.map(inputObject.transform)
.filter(_.isSuccess)
.map { case JsSuccess(value, path) => (value, path) }
.foldLeft(Json.obj()) { (obj, jsValueAndPath) =>
val(jsValue, path) = jsValueAndPath
val transformer = __.json.update(path.json.put(jsValue))
obj.transform(transformer).get
}
}
Usage: 用法:
val input = Json.obj(
"field1" -> Json.obj(
"field2" -> "right result"
),
"field4" -> Json.obj(
"field5" -> "not included"
),
)
val result = filterByPaths(List(JsPath \ "field1" \ "field2"), input)
// {"field1":{"field2":"right result"}}
Problem 问题
This code works fine for JsObjects
. 这段代码对
JsObjects
很好用。 But I can't make it work if there are JsArrays
in the strucure. 但是,如果结构中包含
JsArrays
,则无法使其工作。 I had hoped that my JsPath
could contain an index to look up the field, but that's not the case. 我曾希望我的
JsPath
可以包含一个索引来查找字段,但事实并非如此。 (Don't know why I assumed that, maybe my head was too far in the JavaScript-world) (不知道为什么会这样,也许我的头在JavaScript世界中过高了)
So this would fail to return the first entry in the Array: 因此,这将无法返回Array中的第一个条目:
val input: JsObject = Json.parse("""
{
"arr1" : [{
"field1" : "value1"
}]
}
""").as[JsObject]
val result = filterByPaths(List(JsPath \ "arr1" \ "0"), input)
// {}
Question 题
My question is: How can I return a subset of a json structure that contains arrays? 我的问题是: 如何返回包含数组的json结构的子集?
Alternative solution 替代解决方案
I have the data as a case class first, and I serialize it to Json, and then run filterByPaths
on it. 我首先将数据作为案例类,然后将其序列化为Json,然后在
filterByPaths
上运行filterByPaths
。 Having a Reader
that only creates the json I need in the first place might be a better solution, but creating a Reader
on the fly, with configuration from queryparams seamed a more difficult task, then just stripping down the json afterwards. 首先拥有一个仅创建我需要的json的
Reader
可能是一个更好的解决方案,但是通过使用queryparams进行配置来动态创建一个Reader
带来一项更加艰巨的任务,然后再剥离json。
The example of the returning array element: 返回数组元素的示例:
val input: JsValue = Json.parse("""
{
"arr1" : [{
"field1" : "value1"
}]
}
""")
val firstElement = (input \ "arr1" \ 0).get
val firstElementAnotherWay = input("arr1")(0)
More about this in the Play Framework documentation: https://www.playframework.com/documentation/2.6.x/ScalaJson 有关Play框架文档的更多信息,请访问: https : //www.playframework.com/documentation/2.6.x/ScalaJson
It looks like you got the old issue RuntimeException: expected KeyPathNode
. 看来您遇到了旧问题
RuntimeException: expected KeyPathNode
。 JsPath.json.put
, JsPath.json.update
can't past an object to a nesting array. JsPath.json.put
, JsPath.json.update
不能将对象传递到嵌套数组。
https://github.com/playframework/playframework/issues/943 https://github.com/playframework/playframework/issues/943
https://github.com/playframework/play-json/issues/82 https://github.com/playframework/play-json/issues/82
What you can do: 你可以做什么:
Example of stripping array (point 3): 剥离数组的示例(第3点):
def filterByPaths(paths: List[JsPath], inputObject: JsObject) : JsObject = {
paths
.map(_.json.pick)
.map(inputObject.transform)
.filter(_.isSuccess)
.map { case JsSuccess(value, path) => (value, path)}
.foldLeft(Json.obj()) { (obj, jsValueAndPath) =>
val (jsValue, path) = jsValueAndPath
val arrayStrippedPath = JsPath(path.path.filter(n => !(n.toJsonString matches """\[\d+\]""")))
val transformer = __.json.update(arrayStrippedPath.json.put(jsValue))
obj.transform(transformer).get
}
}
val result = filterByPaths(List(JsPath \ "arr1" \ "0"), input)
// {"arr1":{"field1":"value1"}}
The example 这个例子
The best to handle JSON objects is by using case classes and create implicit Reads and Writes, by that you can handle errors every fields directly. 处理JSON对象的最佳方法是使用案例类并创建隐式的读写操作,这样您就可以直接处理每个字段的错误。 Don't make it complicated.
不要复杂。
Don't use .get()
much recommended to use .getOrElse()
because scala is a type-safe programming language. 不要使用
.get()
多推荐使用.getOrElse()
因为Scala是一种安全的编程语言。
Don't just use any Libraries except you know the process behind it, much better to create your own parsing method with simplified solution to save memory. 不要只使用任何库,除非您知道其背后的过程,否则最好使用简化的解决方案创建自己的解析方法以节省内存。
I hope it will help you.. 希望对您有帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.