How to read nested array elements from JSON? - json

I need to parse a JSON with nested array elements and extract the values.
I am not sure how to use the nested array to set the value of an attribute in output JSON.
This is the input:
[{
"name": "book1",
"id": 18789,
"locations": [{
"state": "mystate",
"phone": 8877887700
}, {
"state": "mystate1",
"phone": 8877887701
}]
},
{
"name": "book2",
"id": 18781,
"locations": [{
"state": "mystate3",
"phone": 8877887711
}, {
"state": "mystate4",
"phone": 8877887702
}]
}]
And this is the expected output:
{
"name": ["book1", "book2"],
"id": ["18789", "18781"],
"states": [
["mystate", "mystate"],
["mystate3", "mystate4"]
]
}
I am trying to use the following JSLT expression:
{
"name" : [for (.)
let s = string(.name)
$s],
"id": [for (.)
let s = string(.id)
$s],
"states": [for (.)
let s = string(.locations)
$s]
}
But I am not sure how to set the states in this case so that I have the value of state in the output.
A solution using JQ or JSONPath may also help.

With JQ it'd be easier than that.
{
name: map(.name),
id: map(.id),
states: map(.locations | map(.state))
}
Online demo

In JSLT you can implement it like this:
{
"name" : [for (.) .name],
"id": [for (.) .id],
"states": flatten([for (.) [for (.locations) .state]])
}
The states key is a bit awkward to implement, as you see. I have thought of making it possible to let path expressions traverse arrays, and if we add that to the language it could be implemented like this:
{
"name" : .[].name,
"id": .[].id,
"states": .[].locations.[].state
}

Related

jOOQ JSON formatting as array of objects

I have the following (simplified) jOOQ query:
val result = context.select(
jsonObject(
key("id").value(ITEM.ID),
key("title").value(ITEM.NAAM),
key("resources").value(
jsonArrayAgg(ITEM_INHOUD.RESOURCE_ID).absentOnNull()
)
)
).from(ITEM).fetch()
Now the output that I want is:
[
{
"id": "0da04cc5-f70c-4fb3-b5c7-dc645d342631",
"title": "Title1",
"resources": [
"8b0f6d5c-67fc-47ca-be77-d1735e7721ce",
"ea0316db-1cfd-46d7-8260-5c1a4e65a0cd"
]
},
{
"id": "0f7e67e6-5187-47e2-9f1d-dab08feba38b",
"title": "Title2"
}
]
result.formtJSON() gives the following output:
{
"fields": [
{
"name": "json_object",
"type": "JSON"
}
],
"records": [
[
{
"id": "0da04cc5-f70c-4fb3-b5c7-dc645d342631",
"title": "Title 1"
}
]
]
}
Disabling the headers with result.formatJSON(JSONFormat.DEFAULT_FOR_RECORDS) will get me:
[
[
{
"id": "0da04cc5-f70c-4fb3-b5c7-dc645d342631",
"title": "Title1",
"resources": [
"8b0f6d5c-67fc-47ca-be77-d1735e7721ce",
"ea0316db-1cfd-46d7-8260-5c1a4e65a0cd"
]
}
],
[
{
"id": "0f7e67e6-5187-47e2-9f1d-dab08feba38b",
"title": "Title2"
}
]
]
where I don't want the extra array.
Further customizing the JSONformatter with result.formatJSON(JSONFormat().header(false).recordFormat(JSONFormat.RecordFormat.OBJECT)) I get:
[
{
"json_object": {
"id": "0da04cc5-f70c-4fb3-b5c7-dc645d342631",
"title": "Title1",
"resources": [
"8b0f6d5c-67fc-47ca-be77-d1735e7721ce",
"ea0316db-1cfd-46d7-8260-5c1a4e65a0cd"
]
}
},
{
"json_object": {
"id": "0f7e67e6-5187-47e2-9f1d-dab08feba38b",
"title": "Title2"
}
}
]
where I don't want the object wrapped in json_object.
Is there a way to get the output I want?
Doing it with Result.formatJSON()
This is clearly a flaw in the jOOQ 3.14.0 implementation of Result.formatJSON(). In the special case where there is only one column, and that column is of type JSON or JSONB, the column name may not really matter, and thus its contents should be flattened into the object describing the row. I've created a feature request for this: https://github.com/jOOQ/jOOQ/issues/10953. It will be available in jOOQ 3.15.0 and 3.14.4. You will be able to do this:
result.formatJSON(JSONFormat().header(false).wrapSingleColumnRecords(false));
The RecordFormat is irrelevant here. This works the same way for RecordFormat.ARRAY and RecordFormat.OBJECT
Doing it directly with SQL
Of course, you can always work around this by moving all the logic into SQL. You probably simplified your query by omitting a JOIN and GROUP BY. I'm assuming this is equivalent to what you want:
JSON result = context.select(
jsonArrayAgg(jsonObject(
key("id").value(ITEM.ID),
key("title").value(ITEM.NAAM),
key("resources").value(
select(jsonArrayAgg(ITEM_INHOUD.RESOURCE_ID).absentOnNull())
.from(ITEM_INHOUD)
.where(ITEM_INHOUD.ITEM_ID.eq(ITEM.ID))
)
))
).from(ITEM).fetchSingle().value1()
Note that JSON_ARRAYAGG() aggregates empty sets into NULL, not into an empty []. If that's a problem, use COALESCE()

Groovy - Parse JSON where only certain values exists in response

I am trying to parse a JSON response that has repeating objects with JsonSlurper to compare to a JDBC query. However, I only want to compare objects where a certain values exist within that object.
If I had a response that looks like this, how would I only parse the objects where the country equals USA or Canada, therefore ignoring anything else?
{
"info": [{
"name": "John Smith",
"phone": "2125557878",
"country": {
"value": "USA"
}
},
{
"name": "Jane Smith",
"phone": "2125551212",
"country": {
"value": "USA"
}
},
{
"name": "Bob Jones",
"phone": "4165558714",
"country": {
"value": "Canada"
}
},
{
"name": "George Tucker",
"phone": "4454547171",
"country": {
"value": "UK"
}
},
{
"name": "Jean Normand",
"phone": "4454547171",
"country": {
"value": "France"
}
}]
}
This is what I have in groovy:
def jsonResponse = context.expand('${RESTRequest#Response}')
def parsedJson = new JsonSlurper().parseText(jsonResponse)
def info = parsedJson.info
def jsonDataObjects = []
info.each { json ->
jsonDataObjects.add(Model.buildJSONData(json))
}
I am building a collection of the elements that I need to compare to a database. How do I only add to that collection where the info.country.value = USA or Canada?
I tried using .findAll like this just to test if I could get it to filter by just one of the countries:
def info = parsedJson.info.country.findAll{it.value == "USA"}
But, when I do that, only the value field is kept. I lose the name and phone from the parse.
Thanks in advance for any assistance.
Did you try
def info = parsedJson.info.findAll{it.country.value == "USA"}
?

Extracting a subset of attributes with JSONPath

I have this JSON code:
{
"A": {
"AB": [{
"ABA": "0",
"ABB": "1",
"ABC": "2"
}]
}
}
I need to use a JSONPath expression that returns that JSON with only ABA and ABC attributes. Something like:
{
"A": {
"AB": [{
"ABA": "0",
"ABC": "2"
}]
}
}
So far I manage to extract either one or all attributes. For example
$.A.AB[*]
or
$.A.AB[*].ABA
Is there a way to extract only two?
Thanks
This will work using the Jayway implementation (Java):
$.A.AB[*]['ABB', 'ABA']
and the result for your input would be:
[
{
"ABB" : "1",
"ABA" : "0"
}
]
You can Compare different providers here:
http://jsonpath.herokuapp.com/

Appending a key value pair to a json object

This is the json object I am working with
{
"name": "John Smith",
"age": 32,
"employed": true,
"address": {
"street": "701 First Ave.",
"city": "Sunnyvale, CA 95125",
"country": "United States"
},
"children": [
{
"name": "Richard",
"age": 7
},
{
"name": "Susan",
"age": 4
},
{
"name": "James",
"age": 3
}
]
}
I want this as another key-value pair :
"collegeId": {
"eventno": "6062",
"eventdesc": "abc"
};
I tried concat but that gave me the result with || symbol and I cdnt iterate. I used spilt but that removes only commas.
concattedjson = JSON.stringify(JSON.parse(json1).concat(JSON.parse(json2)));
How do I add a key pair value to an existing json object ?
I am working in javascript.
This is the easiest way and it's working to me.
var testJson = {
"name": "John Smith",
"age": 32,
"employed": true,
"address": {
"street": "701 First Ave.",
"city": "Sunnyvale, CA 95125",
"country": "United States"
},
"children": [
{
"name": "Richard",
"age": 7
},
{
"name": "Susan",
"age": 4
},
{
"name": "James",
"age": 3
}
]
};
testJson.collegeId = {"eventno": "6062","eventdesc": "abc"};
Just convert the JSON string to an object using JSON.parse() and then add the property. If you need it back into a string, do JSON.stringify().
BTW, there's no such thing as a JSON object. There are objects, and there are JSON strings that represent those objects.
You need to make an object at reference "collegeId", and then for that object, make two more key value pairs there like this:
var concattedjson = JSON.parse(json1);
concattedjson["collegeId"] = {};
concattedjson["collegeId"]["eventno"] = "6062";
concattedjson["collegeId"]["eventdesc"] = "abc";
Assuming that concattedjson is your json object. If you only have a string representation you will need to parse it first before you extend it.
Edit
demo for those who think this will not work.
const newTestJson = JSON.parse(JSON.stringify(testJson));
newTestJson.collegeId = {"eventno": "6062","eventdesc": "abc"};
testJson = newTestJson;

JSON Array Structure Variations

Below are 3 JSON Array structure formats...
The first one, the one outlined at JSON.org, is the one I am familiar with:
Format #1
{"People": [
{
"name": "Sally",
"age": "10"
},
{
"name": "Greg",
"age": "10"
}
]}
The second one is a slight variation that names the elements of the array. I personally don't care for it; you don't name elements of an array in code (they are accessed by index), why name them in JSON?
Format #2
{"People": [
"Person1": {
"name": "Sally",
"age": "10"
},
"Person2": {
"name": "Greg",
"age": "10"
}
]}
This last one is another variation, quite similar to Format #2, but I have a hunch this one is incorrect because it appears to have extra curly braces where they do not belong.
Format #3
{"People": [
{
"Person1": {
"name": "Sally",
"age": "10"
}
},
{
"Person2": {
"name": "Greg",
"age": "10"
}
}
]}
Again, I'm confident that Format #1 is valid as it is the JSON Array format outlined at JSON.org. However, what about Format #2 and Format #3? Are either of those considered valid JSON? If yes, where did those formats come from? I do not see them outlined at JSON.org or on Wikipedia.
Both #1 and #3 are (nearly - there are commas missing) valid JSON, but encode different structures:
#1 gives you an Array of Objects, each with name and age String properties
#3 gives you an Array of Objects, each with a single Object property, each with name and age String properties.
The #2 is invalid: Arrays (as defined by [ ... ]) may not contain property names.
Solution For Format#1
By default:
array=[];
object={};
JSON Code:
var Json = {
People:[]
};
Json.People.push({
"name": "Sally",
"age": "10"
});
Json.People.push({
"name": "Greg",
"age": "10"
});
JSON Result:
{"People":
[
{
"name": "Sally",
"age": "10"
},
{
"name": "Greg",
"age": "10"
}
]
}