Jolt to check non-null value and then add a new field - json

Below is the json input file.
{
"data": {
"no1": 12345,
"cp1": {
"cp1_sub1": "sub1",
"cp2_sub2": "sub2"
},
"cp2": null
}
}
the expectation is like adding a "no1" field inside the "cp1" and "cp2" if it is non-null object.
I have tried with following 2 ways but non of it is working. Is there any way to check null or add a null value with a new key in jolt?
Try 1:
[
{
"operation": "shift",
"spec": {
"data": {
"*": "data.&",
"cp1": {
"#(1,no1)": "data.cp1.no1",
"*": "data.cp1.&"
},
"cp2": {
"#(1,no1)": "data.cp2.no1",
"*": "data.cp2.&"
}
}
}
}
]
Here the problem is it adds "no1" in "cp2".
Try 2:
[
{
"operation": "shift",
"spec": {
"data": {
"*": "data.&",
"cp1": {
"#(1,no1)": "data.cp1.no1",
"*": "data.cp1.&"
},
"cp2": {
"*": {
"#(1,no1)": "data.cp2.no1",
"*": "data.cp2.&"
}
}
}
}
}
]
Here the problem is "cp2" it self removed. If this is correct then how we can add back "cp2": null
If the input is an array like this.
{
"abc": "def",
"data": [
{
"no1": 12345,
"cp1": {
"cp1_sub1": "sub1",
"cp2_sub2": "sub2"
},
"cp2": null
},
{
"no1": 56789,
"cp1": null,
"cp2": {
"cp3_sub1": "sub1",
"cp3_sub2": "sub2"
}
}
]
}
I tried with the same way with #Barbaros answer. but the last step is not working for the array part. Considering cp1 and cp2 as the fixed key and not a dynamic.
[
{
// multiplex the current JSON value in order to use one for logical comparisons later
"operation": "shift",
"spec": {
"data": {
"*": {
"*": "data.[&1].&",
"#(0,cp1)": "data.[&1].temp-cp1",
"#(0,cp2)": "data.[&1].temp-cp2"
}
}
}
},
{
// determine whether the value of the attribute/object is "null"
"operation": "modify-overwrite-beta",
"spec": {
"data": {
"*": {
"temp-cp1": ["=toString", "NuLllLL"],
"temp-cp2": ["=toString", "NuLllLL"]
}
}
}
}
]

We should generate a comparison identifier in order to be prepared for upcoming conditional which will be held within a consequent transformation
[
{
// multiplex the current JSON value in order to use one for logical comparisons later
"operation": "shift",
"spec": {
"data": {
"*": "&1.&",
"#": "New_&1.&"
}
}
},
{
// determine whether the value of the attribute/object is "null"
"operation": "modify-overwrite-beta",
"spec": {
"New_data": {
"data": {
"cp*": ["=toString", "NuLllLL"]
}
}
}
},
{
// use conditional logic based on the results determined within the previous transformation
"operation": "shift",
"spec": {
"New_data": {
"data": {
"cp*": {
"NuLllLL": {
"#(4,data.&1)": "&3.&2"
},
"*": {
"#1": "&3.&2.new_&2",
"#(4,data.no1)": "&3.&2.no1"
},
"*}": { // check out if it's an object
"#(4,data.&1)": "&3.&2",
"#(4,data.no1)": "&3.&2.no1"
}
},
"*": "&1.&"
}
}
}
}
]
the demo on the site http://jolt-demo.appspot.com/ is

Related

JOLT concatenate two strings

I have this collection of driver details and I want to use jolt to copy the properties to concatenate first name and last name within a single property called name
{
"drivers_details": [
{
"first_name": "Doru",
"last_name": "Petre",
"cnp": "1641201390687",
"id_series": "RK",
"id_number": "123456"
},
{
"first_name": "GIGI",
"last_name": "FANE",
"cnp": "16412013906871",
"id_series": "RK",
"id_number": "1234567"
}
]
}
I am using this spec for the shift transformation spec
[
{
"operation": "shift",
"spec": {
"drivers_details": {
"*": {
"cnp": "body.drivers[&1].tin",
"id_series": "body.drivers[&1].id_series",
"id_number": "body.drivers[&1].id_number"
}
}
}
}
]
and this one for modify-overwrite, but it doesn't work how I was expecting
{
"operation": "modify-overwrite-beta",
"spec": {
"drivers_details": {
"*": {
"name": "=concat(#(2,first_name),' ',#(2,last_name))"
}
}
}
}
What is the correct way of doing this?
You can use modify transformation as in the following case, and get rid of names other than newly formed attribute name such as
[
{
"operation": "modify-overwrite-beta",
"spec": {
"drivers_details": {
"*": {
"name": "=concat(#(1,first_name),' ',#(1,last_name))"
}
}
}
},
{
"operation": "remove",
"spec": {
"drivers_details": {
"*": {
"*name": ""
}
}
}
},
{ // this last spec stands only for ordering of the attributes if the ordering and putting the "name" at the top matters.
// So, you might get rid of the "remove" transformation above if this is used. Otherwise keep it.
"operation": "shift",
"spec": {
"drivers_details": {
"*": {
"name": "&2[&1].&",
"cnp": "&2[&1].&",
"id*": "&2[&1].&"
}
}
}
}
]
where those attributes(first/last_name) stays right-hand-side at the current level, so just only need to traverse 1 colon(:) which appears as #(1,..)
You can use this spec without the remove operation:
[
{
"operation": "modify-overwrite-beta",
"spec": {
"*": {
"*": {
"name": "=concat(#(1,first_&),' ',#(1,last_&))"
}
}
}
},
{
"operation": "shift",
"spec": {
"*": {
"*": {
"name": "&2[&1].&",
"cnp": "&2[&1].&",
"id_*": "&2[&1].&"
}
}
}
}
]

JOLT Specification to Transform JSON field value to field name

I am trying to convert the below JSON payload into a JSON which has the field name as the value of the field:
The jolt file that I have is working if field values are different. But if field values are the same then it is giving an array in the response.
Can you please help to provide jolt specifications for this?
Input JSON Payload :
{
"action": {
"allowPartialSuccess": true,
"records": [
{
"ZuoraSubscriptionExtId": "962041ad-e673-492a-a071-5e0ab74ea001",
"CPQSubscriptionID__c": "5640029343"
},
{
"ZuoraSubscriptionExtId": "962041ad-e673-492a-a071-5e0ab74ea001",
"CPQSubscriptionID__c": "5640029343"
}
],
"type": "update"
}
}
`
Expected output JSON Payload :
{
"action" : {
"allowPartialSuccess" : true,
"records" : {
"962041ad-e673-492a-a071-5e0ab74ea001" : {
"CPQSubscriptionID__c" : "5640029343"
}
}, {
"962041ad-e673-492a-a071-5e0ab74ea001" : {
"CPQSubscriptionID__c" : "5640029343"
}
} ,
"type" : "update"
}
}
JOLT specification that I am using :
[
{
"operation": "shift",
"spec": {
"action": {
"allowPartialSuccess": "action.allowPartialSuccess",
"records": {
"*": {
"CPQSubscriptionID__c": "action.records.#(1,ZuoraSubscriptionExtId).CPQSubscriptionID__c"
}
},
"type": "action.type"
}
}
}
]
You can use this shift transformation spec
[
{
"operation": "shift",
"spec": {
"*": {
"*": "&1.&", // &1 replicates the literal "action"
"records": {
"*": {
"C*": "&3.&2.#(1,ZuoraSubscriptionExtId).&" // &3 replicates the literal "action" (by going three level up the tree), &2 for "records", & replicates the current level attribute
}
}
}
}
}
]
the demo on the site http://jolt-demo.appspot.com/ is
Your expected output is wrong in the question.
If you want an object in your record, You can use this spec:
[
{
"operation": "shift",
"spec": {
"*": {
"&": "&1.&",
"records": {
"*": {
"CPQSubscriptionID__c": "&3.&2.#(1,ZuoraSubscriptionExtId).CPQSubscriptionID__c"
}
}
}
}
},
{
"operation": "cardinality",
"spec": {
"*": {
"records": {
"*": {
"*": "ONE"
}
}
}
}
}
]
And if you want an array in your output. You can use this spec:
[
{
"operation": "shift",
"spec": {
"*": {
"*": "&1.&",
"records": {
"*": {
"CPQSubscriptionID__c": "&3.&2[].#(1,ZuoraSubscriptionExtId).CPQSubscriptionID__c"
}
}
}
}
}
]

JOLT Specification for converting filed value to field name

I am trying to convert the below JSON payload into a JSON that has the field name as the value of the field:
The jolt file that I have is working if field values are different. But if field values are the same then it is giving an array in the response.
Can you please help to provide jolt specifications for this?
Input JSON Payload:
{
"action": {
"Success": true,
"records": [
{
"Id": "Test_abc",
"SubscriptionID": "ID_1"
},
{
"Id": "Test_abc",
"SubscriptionID": "ID_2"
},
{
"Id": "Test_xyz",
"SubscriptionID": "ID_3"
}
],
"type": "update"
}
}
Expected output:
{
"action": {
"Success": true,
"records": {
"Test_abc": {
"SubscriptionID": "ID_1"
},
"Test_abc": {
"SubscriptionID": "ID_2"
},
"Test_xyz": {
"SubscriptionID": "ID_3"
}
},
"type": "update"
}
}
Solution not found yet.
You can use the following shift transformation spec
[
{
"operation": "shift",
"spec": {
"*": {
"*": "&1.&", // &1 replicates the literal "action"
"records": {
"*": {
"S*": "&3.&2.#(1,Id).&" // &3 replicates the literal "action" (by going three level up the tree), &2 for "records", & replicates the current level attribute
}
}
}
}
}
]
presumingly converting one of the Id value from Test_abc to another one such as Test_def, since the desired output is wrong as a JSON value(There cannot be more than one object with the same tag at the same level)
Your output is wrong. You can't have multiple objects with the same keys.
If You want to support all objects of records array, You should bring them into an array like this spec:
[
{
"operation": "shift",
"spec": {
"*": {
"*": "&1.&",
"records": {
"*": {
"S*ID": "&3.&2[].#(1,Id).&"
}
}
}
}
}
]
But, if you want to have an object as your records in the output, You should remove the duplicate ID like this spec:
[
{
"operation": "shift",
"spec": {
"*": {
"*": "&1.&",
"records": {
"*": {
"S*ID": "&3.&2.#(1,Id).&"
}
}
}
}
},
{
"operation": "cardinality",
"spec": {
"*": {
"records": {
"*": {
"*": "ONE"
}
}
}
}
}
]

Unexpected null elements in output array

EDIT: Now after 16 hours break I realized I have been misreading the results for hours - I didn't notice that there is null in all cases, so the behavior is consistent unlike I claim in this question (facepalm). However I decided not to delete this question but only close it as there is already useful answers.
Consider the following input JSON:
{
"widgets": [
{
"type": "FOO",
"id": "F1"
},
{
"type": "ZAP",
"id": "Z1"
},
{
"type": "BAR",
"id": "B1"
}
]
}
The following transformation:
[
{
"operation": "shift",
"spec": {
"widgets": {
"*": {
"type": {
"FOO": {
"#(2,id)": "widgets[&3].fooId"
},
"BAR": {
"#(2,id)": "widgets[&3].barId"
}
}
}
}
}
}
]
creates the expected (correct) output. EDIT I misread this output - I didn't realize there is 3 elements where one element is null but I though there is only 2 non-null elements:
{
"widgets": [
{
"fooId": "F1"
},
null,
{
"barId": "B1"
}
]
}
However the following transformation creates the unexpected output:
[
{
"operation": "shift",
"spec": {
"widgets": {
"*": {
"type": {
"BAR": {
"#(2,id)": "widgets[&3].barId"
}
}
}
}
}
}
]
This is the actual (wrong) output:
{
"widgets": [
null,
null,
{
"barId": "B1"
}
]
}
This is the expected (correct) output:
{
"widgets": [
{
"barId": "B1"
}
]
}
Why sometimes there is null elements in the widgets array and sometimes there is not? How I can avoid them?
Based on the many other SO questions the following operation:
{
"operation": "modify-overwrite-beta",
"spec": {
"*": "=recursivelySquashNulls"
}
}
should remove the null values, but why those are not removed in the following transformation?
[
{
"operation": "shift",
"spec": {
"widgets": {
"*": {
"type": {
"BAR": {
"#(2,id)": "widgets[&3].barId"
}
}
}
}
}
},
{
"operation": "modify-overwrite-beta",
"spec": {
"*": "=recursivelySquashNulls"
}
}
]
I'm observing this behavior in http://jolt-demo.appspot.com/
The first output keeps null as well(I don't know if it should appear in the desired output). Since the index(which is 1) of the object having "type": "ZAP" stays in the middle of the indexes(0,1,2), but not at the end, then doesn't vanish at that level.
Btw, squashNulls especially no impact for the objects nested within array. Indeed, it has some bugs and documented as fixed for version 0.1.6.
You can rather use the following spec which doesn't have square-bracketed indexes such as
[
{
"operation": "shift",
"spec": {
"*": {
"*": {
"type": {
"FOO|BAR": {
"#(2,id)": "&4.&1.&1Id"
}
}
}
}
}
},
{
"operation": "shift",
"spec": {
"*": {
"*": {
"#": "&2[]"
}
}
}
}
]
This spec will help you resolve this query :
1)
Actually recursivelySquashNulls will work if you keep the array in a object for eg: I kept it under test object and made it to previous one.
This spec will resolve your issue :
[
{
"operation": "shift",
"spec": {
"widgets": {
"*": {
"type": {
"BAR": {
"#(2,id)": "widgets[&3].barId"
}
}
}
}
}
}, {
"operation": "shift",
"spec": {
"*": "test.&"
}
},
{
"operation": "modify-overwrite-beta",
"spec": {
"*": "=recursivelySquashNulls"
}
},
{
"operation": "shift",
"spec": {
"test": {
"*": "&"
}
}
}
]
It looks like the web application in http://jolt-demo.appspot.com/ is running old version 0.1.1 that in this case behaves a bit differently than the newer versions.
At the moment the latest version available in Maven Central seems to be 0.1.7:
https://central.sonatype.dev/artifact/com.bazaarvoice.jolt/jolt-core/0.1.7/versions
thought the Github release page only claims latest to be 0.1.6:
https://github.com/bazaarvoice/jolt/releases/tag/jolt-0.1.6
I have the impression that the very powerful and useful Jolt library is not getting all the care it deserves :(
squashNull seems to work ok in Java code when using version 0.1.7.
Here is my final transformation that works as expected with http://jolt-demo.appspot.com/ based on answer by Barbaros Özhan:
[
{
"operation": "modify-overwrite-beta",
"spec": {
"widgets": {
"*": {
"type": "=toLower"
}
}
}
},
{
"operation": "shift",
"spec": {
"widgets": {
"*": {
"type": {
"foo|bar": {
"#(2,id)": "&4.&1.&1Id"
}
}
}
}
}
},
{
"operation": "shift",
"spec": {
"widgets": {
"*": {
"#": "&2[]"
}
}
}
}
]

Compare and map values between two array of objects in JOLT

I need to map the headers and row values based on the dataKey value.
Input JSON
{
"headers": [
{
"dataKey": "col-0",
"displayName": "Product"
},
{
"dataKey": "col-1",
"displayName": "Dimension"
},
{
"dataKey": "col-2",
"displayName": "Output type "
}
],
"rows": [{
"col-0": "Medium ",
"col-1": "300x250",
"col-2": "HTML [Animate]"
}]
}
Expected Output
{
"Data" : {
"1" : {
"Product":"Medium",
"Dimension":"300x250",
"Output type":"HTML [Animate]"
}
}
}
Spec:
This is the JOLT Spec i am using currently it is not producing the expected ouptut
[
{
"operation": "shift",
"spec": {
"headers": {
"*": {
"displayName": {
"*": {
"#(2,dataKey)": {
"$": "Data.1.&",
"*": {
"#(6,rows.&)": "Data.1.&"
}
}
}
}
}
}
}
}
]
Please provide the jolt spec for above scanario. i tried but not able to get the expected result.
[
{
// segregate values of the same key and form respective arrays.
"operation": "shift",
"spec": {
"headers": {
"*": {
"displayName": "#(1,dataKey)"
}
},
"rows": {
"*": {
"*": "&"
}
}
}
},
{
// put every value array into temp array
"operation": "shift",
"spec": {
"*": "temp[]"
}
},
{
// map first index element as key and second index element as a value into the output
"operation": "shift",
"spec": {
"temp": {
"*": {
"1": "Data.1.#(1,[0])"
}
}
}
}
]