如何根据条件筛选 JSON 数组结果?
How to filter JSON array results based on condition?
我正在使用 Scala Play 2.7.2 并已阅读 ScalaJsonTransformers and ScalaJson。调用 JSON API 后,我得到(简化的 MCVE)结果如下:
{
"type": "searchset",
"total": 5,
"entry": [
{
"start": "2019-06-07T09:00:00",
"end": "2019-06-07T11:00:00",
"id": "55"
},
{
"start": "2019-06-07T13:00:00",
"end": "2019-06-07T15:00:00",
"id": "56"
},
{
"start": "2019-06-07T16:00:00",
"end": "2019-06-07T17:00:00",
"id": "60"
},
{
"start": "2019-06-10T11:00:00",
"end": "2019-06-10T12:00:00",
"id": "58"
},
{
"start": "2019-06-11T14:00:00",
"end": "2019-06-11T15:00:00",
"id": "61"
}
]
}
并且我想过滤结果并仅选择满足条件的结果,例如,过滤掉结束日期大于特定日期 val to = new DateTime("2019-06-10T00:00:00")
的结果并做一些事情:
(json \ "end").filter(new DateTime(_).isBefore(to.toDate.getTime))...
但这不起作用,因为结果是选择而不是整个 json 节点,此外它也离开外部。
解决方案应输出结果:
{
"type": "searchset",
"total": 3,
"entry": [
{
"start": "2019-06-07T09:00:00",
"end": "2019-06-07T11:00:00",
"id": "55"
},
{
"start": "2019-06-07T13:00:00",
"end": "2019-06-07T15:00:00",
"id": "56"
},
{
"start": "2019-06-07T16:00:00",
"end": "2019-06-07T17:00:00",
"id": "60"
}
}
如何使用 Play JSON 完成此操作?
对于 coast-to-coast 设计尝试像这样定义
val to = new DateTime("2019-06-10T00:00:00")
val endDateFilterTransformer = (__ \ 'entry).json.update(__.read[JsArray].map {
case JsArray(values) => JsArray(values.filter(v => (v \ "end").as[DateTime].isBefore(to)))
})
val outJson = json.transform(endDateFilterTransformer)
println(outJson.get)
输出
{
"entry": [
{
"start": "2019-06-07T09:00:00",
"end": "2019-06-07T11:00:00",
"id": "55"
},
{
"start": "2019-06-07T13:00:00",
"end": "2019-06-07T15:00:00",
"id": "56"
},
{
"start": "2019-06-07T16:00:00",
"end": "2019-06-07T17:00:00",
"id": "60"
}
],
"total": 5,
"type": "searchset"
}
或者 JSON 面向对象设计尝试反序列化为模型
case class Entry(start: DateTime, end: DateTime, id: String)
object Entry {
implicit val format = Json.format[Entry]
}
case class Record(`type`: String, total: Int, entry: List[Entry])
object Record {
implicit val format = Json.format[Record]
}
然后使用常规 Scala 方法进行过滤
val to = new DateTime("2019-06-10T00:00:00")
val record = Json.parse(raw).as[Record]
val filteredRecord = record.copy(entry = record.entry.filter(_.end.isBefore(to)))
然后像这样反序列化回 json:
Json.toJson(filteredRecord)
输出
{
"type": "searchset",
"total": 5,
"entry": [
{
"start": "2019-06-07T09:00:00.000+01:00",
"end": "2019-06-07T11:00:00.000+01:00",
"id": "55"
},
{
"start": "2019-06-07T13:00:00.000+01:00",
"end": "2019-06-07T15:00:00.000+01:00",
"id": "56"
},
{
"start": "2019-06-07T16:00:00.000+01:00",
"end": "2019-06-07T17:00:00.000+01:00",
"id": "60"
}
]
}
我们使用 play-json-joda
进行 DateTime
序列化
libraryDependencies += "com.typesafe.play" %% "play-json-joda" % "2.7.3"
import play.api.libs.json.JodaWrites._
import play.api.libs.json.JodaReads._
我正在使用 Scala Play 2.7.2 并已阅读 ScalaJsonTransformers and ScalaJson。调用 JSON API 后,我得到(简化的 MCVE)结果如下:
{
"type": "searchset",
"total": 5,
"entry": [
{
"start": "2019-06-07T09:00:00",
"end": "2019-06-07T11:00:00",
"id": "55"
},
{
"start": "2019-06-07T13:00:00",
"end": "2019-06-07T15:00:00",
"id": "56"
},
{
"start": "2019-06-07T16:00:00",
"end": "2019-06-07T17:00:00",
"id": "60"
},
{
"start": "2019-06-10T11:00:00",
"end": "2019-06-10T12:00:00",
"id": "58"
},
{
"start": "2019-06-11T14:00:00",
"end": "2019-06-11T15:00:00",
"id": "61"
}
]
}
并且我想过滤结果并仅选择满足条件的结果,例如,过滤掉结束日期大于特定日期 val to = new DateTime("2019-06-10T00:00:00")
的结果并做一些事情:
(json \ "end").filter(new DateTime(_).isBefore(to.toDate.getTime))...
但这不起作用,因为结果是选择而不是整个 json 节点,此外它也离开外部。
解决方案应输出结果:
{
"type": "searchset",
"total": 3,
"entry": [
{
"start": "2019-06-07T09:00:00",
"end": "2019-06-07T11:00:00",
"id": "55"
},
{
"start": "2019-06-07T13:00:00",
"end": "2019-06-07T15:00:00",
"id": "56"
},
{
"start": "2019-06-07T16:00:00",
"end": "2019-06-07T17:00:00",
"id": "60"
}
}
如何使用 Play JSON 完成此操作?
对于 coast-to-coast 设计尝试像这样定义
val to = new DateTime("2019-06-10T00:00:00")
val endDateFilterTransformer = (__ \ 'entry).json.update(__.read[JsArray].map {
case JsArray(values) => JsArray(values.filter(v => (v \ "end").as[DateTime].isBefore(to)))
})
val outJson = json.transform(endDateFilterTransformer)
println(outJson.get)
输出
{
"entry": [
{
"start": "2019-06-07T09:00:00",
"end": "2019-06-07T11:00:00",
"id": "55"
},
{
"start": "2019-06-07T13:00:00",
"end": "2019-06-07T15:00:00",
"id": "56"
},
{
"start": "2019-06-07T16:00:00",
"end": "2019-06-07T17:00:00",
"id": "60"
}
],
"total": 5,
"type": "searchset"
}
或者 JSON 面向对象设计尝试反序列化为模型
case class Entry(start: DateTime, end: DateTime, id: String)
object Entry {
implicit val format = Json.format[Entry]
}
case class Record(`type`: String, total: Int, entry: List[Entry])
object Record {
implicit val format = Json.format[Record]
}
然后使用常规 Scala 方法进行过滤
val to = new DateTime("2019-06-10T00:00:00")
val record = Json.parse(raw).as[Record]
val filteredRecord = record.copy(entry = record.entry.filter(_.end.isBefore(to)))
然后像这样反序列化回 json:
Json.toJson(filteredRecord)
输出
{
"type": "searchset",
"total": 5,
"entry": [
{
"start": "2019-06-07T09:00:00.000+01:00",
"end": "2019-06-07T11:00:00.000+01:00",
"id": "55"
},
{
"start": "2019-06-07T13:00:00.000+01:00",
"end": "2019-06-07T15:00:00.000+01:00",
"id": "56"
},
{
"start": "2019-06-07T16:00:00.000+01:00",
"end": "2019-06-07T17:00:00.000+01:00",
"id": "60"
}
]
}
我们使用 play-json-joda
进行 DateTime
序列化
libraryDependencies += "com.typesafe.play" %% "play-json-joda" % "2.7.3"
import play.api.libs.json.JodaWrites._
import play.api.libs.json.JodaReads._