Decode a nested array with circe-optics - scala

I have JSON like this:
"data": {
"project": {
"activityChildren": [
{
"id": 2,
"parents": [
{
"id": 1
}
]
},
]
}
}
I'd like to decode this to List[(Long, List[Long])] with circe-optics. I got as far as:
val activityParents: Map[Long, List[Long]] = root.data.activityChildren.each.json
.getAll(json)
.flatMap { activity =>
root.id.long.getOption(activity).map(_ -> root.parents.each.long.getAll(activity))
}
.toMap
I wonder whether it's possible to define a single lens for this that just turns the JSON into the desired map without explicitly mapping over the intermediate array. If so, how?

Related

use JsLookup for multiple level array using play Json for lists with objects and simple lists

i have a function that exctract from a json list of elements based on the path i give it.
the func looks like this:
def findAllValuesAtPath(jsValue: JsObject, path: String): List[JsValue] = {
val jsPath = JsPath(path
.split("\\[\\*]\\.")
.flatMap(s => s.split("\\.")
.map(RecursiveSearch)
).toList)
jsPath(jsValue)
}
for example:
{
"person": {
"kids": [
{
"name": "josh",
"age": 5
},
{
"name": "julia",
"age": 13
}
]
}
}
now if i give the path - "person.kids[*].name" I will get list of their names List("josh", "julia") which its what i want.
but if the list of kids were just simple list like:
{
"person": {
"kids": [
"josh",
"julia"
]
}
}
and i will give the path - "person.kids[*]" I will get empty list List() and I want to get this as List("josh", "julia") (without the brakets)
do you see any way to improve my func to handle both cases?

Wiremock: how to validate ALL objects in an array

Using wiremock-standalone (version 2.29.1), I want to verify a request with its body holding an array of objects, containing optional properties.
For instance, consider this request:
Request body (JSON format)
{
"foo": [
{ "bar": "1" },
{ "qux": "oh hai" },
{ "bar": "ohnoes" }
]
}
And let's say I want to match requests only if all the foo.bar attributes are either present, or contain only a single digit (it's only for the sake of example). The example above should not match (the third object has a bar attributes with non-digits characters).
I tried different approches, and the closest I got is this:
{
"matchesJsonPath": {
"expression": "$.foo[*].bar",
"or": [
{ "matches": "^\\d$" },
{ "absent": true }
]
}
}
There are 2 problems:
if there is no bar attribute at all, the request does not match
if at least 1 bar attribute passes the check, then the whole request passes, even though other bar values are invalid (the example above passes)
Does anyone know how to create such a rule in wiremock?
I found a possible solution, maybe not the easiest but it works.
Following your example:
request:
{
"foo": [
{ "bar": "1" },
{ "qux": "oh hai" },
{ "bar": "ohnoes" }
]
}
This bodyPatterns file works for validate each field is present and it has the value given:
"bodyPatterns" : [
{
"matchesJsonPath": "$.foo[?(#.bar == '1')]"
},
{
"matchesJsonPath": "$.foo[?(#.qux == 'oh hai')]"
},
{
"matchesJsonPath": "$.foo[?(#.bar == 'ohnoes')]"
}
]
For reference, the following post helped me a lot:
Wiremock matchesJsonPath checking array values ignoring the order

Filtering vales in Dataweave

I am trying to filter out vales matching a variable using dataweave.
result = {
"drives": [{
"id": "0AEBByqXZ0xb4Uk9PVA",
"name": "QA-zz-SFJobs-Contacts"
}, {
"id": "0AC_FdkeL63mHUk9PVA",
"name": "QA"
}]
}
above is my payload.
Am trying below code
%dw 2.0
output application/json
---
{
drives: payload.result.drives[0] filter ((item, index) -> item.name == "QA")
}
which gives me error
error:
You called the function 'Value Selector' with these arguments:
1: String ("{"drives":[{"id":"0AEBByqXZ0xb4Uk9PVA","name":"QA-zz-SFJobs-Contact...)
2: Name ("drives")
But it expects one of these combinations:
(Array, Name)
(Array, String)
(Date, Name)
(DateTime, Name)
(LocalDateTime, Name)
(LocalTime, Name)
(Object, Name)
(Object, String)
(Period, Name)
(Time, Name)
5| drives: payload.result.drives[0] filter ((item, index) -> item.name == vars.folderName)
^^^^^^^^^^^^^^^^^^^^^
Trace:
at filter (line: 5, column: 13)
at main (line: 5, column: 38)" evaluating expression: "%dw 2.0
output application/json
{
drives: payload.result.drives[0] filter ((item, index) -> item.name == vars.folderName)
}".
Expected output:
{
"id": "0AC_FdkeL63mHUk9PVA",
"name": "QA"
}
how can i achieve this?
The input should be a valid "JSON" like :
{
"result": {
"drives": [{
"id": "0AEBByqXZ0xb4Uk9PVA",
"name": "QA-zz-SFJobs-Contacts"
},
{
"id": "0AC_FdkeL63mHUk9PVA",
"name": "QA"
}]
}
}
Here applying the logic above :
{
drives: payload.result.drives[0]
}
returns output as :
{
"drives": {
"id": "0AEBByqXZ0xb4Uk9PVA",
"name": "QA-zz-SFJobs-Contacts"
}
}
which is a single object containing object, and hence filter method cannot be applied as filter is applicable on arrays and arrays of objects.
To try your dataweave code snippet you can use the online dataweave editor :
Online Dataweave Editor
which can give you better insights.
As #Bibek mentioned, you need a properly formatted json as input:
{
"result": {
"drives": [{
"id": "0AEBByqXZ0xb4Uk9PVA",
"name": "QA-zz-SFJobs-Contacts"
},
{
"id": "0AC_FdkeL63mHUk9PVA",
"name": "QA"
}]
}
}
And then you can use filter on an array (drives), so your query would be:
%dw 2.0
output application/json
---
payload.result.drives filter ((item, index) -> item.name == "QA")
If you use "drives[0]" you are selecting the first element in the array, so, you don't need to use filter (unless the first element also contains an array inside of it, which is not the case)

How to convert inner json part into object in dart/flutter

I need to convert every element of 'content' array to object.
Here is json:
{
"content": [
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"author": {
"userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
},
"createDate": "2020-01-30T20:18:29.764Z",
"executor": {
"userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
},
}
],
"first": true,
"numberOfElements": 0,
}
The problem is that 'content' array is inside json, and its parts as executor and author has to be objects too, and I don't know how to reach it and parse.
How it can be done? Any help, thanks.
You access the elements like this:
var decoded = json.decode(j);
var inner = decoded['content'][0]; // if you expect more than one entry, iterate the list
print(inner['id']); // -> 3fa85f64-5717-4562-b3fc-2c963f66afa6
print(inner['createDate']);
print(inner['author'].runtimeType); // another Map<String, dynamic> as expected
print(inner['author']['userId']);
You can create Dart classes to model, for example, a 'user' if you want.

Spark Scala - How to construct Scala Map from nested JSON?

I've a nested json data with nested fields that I want to extract and construct a Scala Map.
Heres the sample JSON:
"nested_field": [
{
"airport": "sfo",
"score": 1.0
},
{
"airport": "phx",
"score": 1.0
},
{
"airport": "sjc",
"score": 1.0
}
]
I want to use saveToES() and construct a Scala Map to index the field into ES index with mapping as below:
"nested_field": {
"properties": {
"score": {
"type": "double"
},
"airport": {
"type": "keyword",
"ignore_above": 1024
}
}
}
The json file is read into the dataframe using spark.read.json("example.json"). Whats the right way to construct the Scala Map in this case?
Thanks for any help!
You can do it using the below sample code
import org.json4s.DefaultFormats
import org.json4s.jackson.JsonMethods.parse
case class AirPortScores(airport: String, score: Double)
case class JsonRulesHandler(airports: List[AirPortScores])
val jsonString: String = """{"airports":[{"airport":"sfo","score":1},{"airport":"phx","score":1},{"airport":"sjc","score":1}]}"""
def loadJsonString(JsonString: String): JsonRulesHandler = {
implicit val formats: DefaultFormats.type = org.json4s.DefaultFormats
parse(JsonString).extract[JsonRulesHandler]
}
val parsedJson: JsonRulesHandler = loadJsonString(jsonString)
parsedJson.airports.foreach(println)//you can select parsedJson.airport or scores
//below ouput
AirPortScores(sfo,1.0)
AirPortScores(phx,1.0)
AirPortScores(sjc,1.0)