JOLT Transformation Rename & Remove based on null value - json

I want to transform this JSON:
[
{
"payload": {
"before": {
"order_id": 3110445250,
"data": "2022-06-10",
"ora": "08:08:00",
"test1": "2022-06-10T00:00:00.000Z",
"test2": "2022-06-10T03:00:00.000Z"
},
"after": null,
"source": {
"file": "delta.000002",
"pos": 8362,
"row": 0,
"thread": null,
"query": null
},
"op": "c",
"ts_ms": 1654851760103,
"transaction": null
}
}
]
Desired output:
if "after" is null then remove "after" and rename "before" to "final"
else if "before" is null then remove "before" and rename after to "final"
else if "after" is not null and "before" is not null then remove "before" and rename after to "final"
[
{
"payload": {
"before": {
"order_id": 3110445250,
"data": "2022-06-10",
"ora": "08:08:00",
"test1": "2022-06-10T00:00:00.000Z",
"test2": "2022-06-10T03:00:00.000Z"
},
"source": {
"file": "delta.000002",
"pos": 8362,
"row": 0,
"thread": null,
"query": null
},
"op": "c",
"ts_ms": 1654851760103,
"transaction": null
}
}
]
Thanks a lot!

You can use a conditional logic within a shift transformation after determining the sizes of before/after objects/attributes through use of a modify transformation in which we compute their respective sizes whether they return a value. In cases the value doesn't return, then -1 is assigned to determine the element(object or attribute) to be null such as
[
{
"operation": "modify-overwrite-beta",
"spec": {
"*": {
"payload": {
"before_sz": ["=size(#(1,before))", -1],
"after_sz": ["=size(#(1,after))", -1]
}
}
}
},
{
"operation": "shift",
"spec": {
"*": {
"payload": {
"before_sz": {
"-1": {
"#(2,after_sz)": {
"-1": { "": "" },
"*": { "#(4,after)": "[&6].&5.final" }
}
},
"*": {
"#(2,after_sz)": {
"-1": { "#(4,before)": "[&6].&5.final" },
"*": { "#(4,after)": "[&6].&5.final" }
}
}
},
"*": "[&2].&1.&"
}
}
}
},
{
"operation": "remove",
"spec": {
"*": {
"payload": {
"after_sz": "",
"after": "",
"before_sz": "",
"before": ""
}
}
}
},
{
"operation": "sort"
}
]
that will return
[
{
"payload": {
"final": {
"data": "2022-06-10",
"ora": "08:08:00",
"order_id": 3110445250,
"test1": "2022-06-10T00:00:00.000Z",
"test2": "2022-06-10T03:00:00.000Z"
},
"op": "c",
"source": {
"file": "delta.000002",
"pos": 8362,
"query": null,
"row": 0,
"thread": null
},
"transaction": null,
"ts_ms": 1654851760103
}
}
]
for the current input as a sample case.
PS.: as a missing case for the question : if both after/before are null, then both are removed within this solution.
Edit : If the input is not nested within square brackets(as you asked as an extra case), then convert the spec to this one :
[
{
"operation": "modify-overwrite-beta",
"spec": {
"payload": {
"before_sz": ["=size(#(1,before))", -1],
"after_sz": ["=size(#(1,after))", -1]
}
}
},
{
"operation": "shift",
"spec": {
"payload": {
"before_sz": {
"-1": {
"#(2,after_sz)": {
"-1": { "": "" },
"*": { "#(4,after)": "&5.final" }
}
},
"*": {
"#(2,after_sz)": {
"-1": { "#(4,before)": "&5.final" },
"*": { "#(4,after)": "&5.final" }
}
}
},
"*": "&1.&"
}
}
},
{
"operation": "remove",
"spec": {
"payload": {
"after_sz": "",
"after": "",
"before_sz": "",
"before": ""
}
}
},
{
"operation": "sort"
}
]

Related

Jolt Transform to append extracted data

I'm new to Jolt Transform and have some EDI data that I want to transform. I want to keep the original data and append a few extracted elements in order to make it easier for a downstream process to get to. Here's a sample:
Input
{
"id": "2000",
"segments": [
{
"REF02": "xxxxxxxxxxxx",
"REF01": "0F",
"id": "REF"
},
{
"REF02": "yyyyyyyyyyyy",
"REF01": "1L",
"id": "REF"
}
],
"loops": [
{
"id": "2100",
"segments": []
},
{
"id": "2100",
"segments": [],
"loops": [
{
"id": "2300",
"segments": [
{
"DTP01": "348",
"DTP03": "20220101",
"DTP02": "D8",
"id": "DTP"
},
{
"DTP01": "349",
"DTP03": "20221231",
"DTP02": "D8",
"id": "DTP"
}
]
}
]
}
]
}
Desired Output
{
"ext": {
"subscriber": "xxxxxxxxxxxx",
"start": "20220101"
},
"id": "2000",
"segments": [
{
"REF02": "xxxxxxxxxxxx",
"REF01": "0F",
"id": "REF"
},
{
"REF02": "yyyyyyyyyyyy",
"REF01": "1L",
"id": "REF"
}
],
"loops": [
{
"id": "2100",
"segments": []
},
{
"id": "2100",
"segments": [],
"loops": [
{
"id": "2300",
"segments": [
{
"DTP01": "348",
"DTP03": "20220101",
"DTP02": "D8",
"id": "DTP"
},
{
"DTP01": "349",
"DTP03": "20221231",
"DTP02": "D8",
"id": "DTP"
}
]
}
]
}
]
}
That is, I'd like to append the ext element - copying values from the original.
In xpath terms, the extracted values' paths look something like this:
subscriber :
/segments[../id eq "2000"]/..[REF01 eq "0F"]/REF02/text()
start :
/loops[../id eq "2000"]/../segments[../id eq "2100"])[1]/..
[id eq "NM1" and NM101 eq "IL"][DTP01 eq "348"]/DTP03/text()
Thanks for the help.
I ended up with this solution. If there's any feedback on streamlining, making more elegant, let me know.
[
{
"operation": "default",
"spec": {
"dummy": {}
}
},
{
"operation": "shift",
"spec": {
"dummy": {
"#2,segments": {
"*": {
"REF01": {
"0F": {
"#2,REF02": "ext.subscriber"
}
}
}
},
"#2,loops": {
"*": {
"id": {
"2100": {
"#2,loops": {
"*": {
"id": {
"2300": {
"#2,segments": {
"*": {
"DTP01": {
"348": {
"#2,DTP03": "ext.start"
}
}
}
}
}
}
}
}
}
}
}
}
},
"id": "id",
"segments": "segments",
"loops": "loops"
}
}
]
You can replicate the whole content by use of "#": "" within a shift transformation while adding less curly braces to nest the inner stuff, at the same time determining the paths to search to be used in the next spec such as
[
{
"operation": "shift",
"spec": {
"#": "",
"segments": {
"*": {//indexes of the array
"#REF02": "ext.su.#REF01"
}
},
"loops": {
"*": {//indexes of the array
"#loops": {
"*": {//indexes of the array
"#segments": {
"*": {//indexes of the array
"#DTP03": "ext.st.#5,id.#3,id.#DTP01"
}
}
}
}
}
}
}
},
{
"operation": "shift",
"spec": {
"ext": {
"#su.0F": "&1.subscriber",
"#st.2100.2300.348": "&1.start"
},
"*": "&" //replicate the other attributes/arrays/objects
}
}
]

JOLT apply different transformations based on success of the call

I'm calling a rest web service and I receive the following responses depending if the call was successful or not.
Input 1:
{
"success": true,
"data": {
"series": "XX/32/V32/LM",
"number": 242,
"end_date": "31/12/2023",
"premium": "2309.68",
"premium_net": "2286.58",
"total_premium": 2494.46,
"commission": 1,
"installments": [
{
"number": 1,
"due_date": "30/12/2022",
"value": "2494.46",
"currency": "RON"
}
],
"reference_premium": 1061,
"direct_settlement_cover": 1,
"direct_settlement": 184.78,
"direct_settlement_net": 182.93,
"bm": "B0",
"exclusion_countries": [
"BY",
"IL",
"IR",
"MA",
"RUS",
"TN",
"UA"
]
},
"message": "Polița a fost emisă cu succes"
}
Input 2:
{
"success": false,
"message": "Eroare validare date",
"data": {
"pay_document": [
"Trebuie să menționați modalitatea de plată"
]
}
}
And I wrote the following operations that work individually
Success spec:
[
{
"operation": "shift",
"spec": {
"message": "body.info_message",
"data": {
"#1": "body.good_id",
"series": "body.policy_series",
"number": "body.policy_number",
"end_date": "body.policy_end_date",
"direct_settlement_cover": {
"1": {
"#Decontare directa": "clauses[0].clause_name",
"#1": "clauses[0].clause_id"
}
},
"direct_settlement": "clauses[0].premium",
"installments": {
"*": {
"number": "body.installments[&1].number",
"value": "body.installments[&1].amount",
"currency": "body.installments[&1].currency",
"due_date": "body.installments[&1].due_date"
}
}
}
}
},
{
"operation": "modify-overwrite-beta",
"spec": {
"body": {
"good_id": "=toInteger"
}
}
}
]
Error spec:
[
{
"operation": "shift",
"spec": {
"message": "body.info_message",
"data": {
"*": {
"*": "body.error_message"
}
}
}
},
{
"operation": "modify-overwrite-beta",
"spec": {
"*": {
"error_message": "=join(' | ',#(1,&))"
}
}
}
]
Now I'm trying to combine those two and display the error messages if success is false or return the model to be saved. I tried to place success inside my transformation but it keeps returning null. what is the best practice in this regard...
You can use this spec:
I'm just adding the first shift operator and changing the data key with true and false in your code. So the final code is like the below:
[
{
"operation": "shift",
"spec": {
"*": "&",
"data": "#(1,success)"
}
},
{
"operation": "shift",
"spec": {
"message": "body.info_&",
"true": {
"#1": "body.good_id",
"series": "body.policy_&",
"number": "body.policy_&",
"end_date": "body.policy_&",
"direct_settlement_cover": {
"1": {
"#Decontare directa": "clauses[0].clause_name",
"#1": "clauses[0].clause_id"
}
},
"direct_settlement": "clauses[0].premium",
"installments": {
"*": {
"*": "body.&2[&1].&",
"value": "body.&2[&1].amount"
}
}
},
"false": {
"*": {
"*": "body.error_message"
}
}
}
},
{
"operation": "modify-overwrite-beta",
"spec": {
"*": {
"good_id": "=toInteger",
"error_message": "=join(' | ',#(1,&))"
}
}
}
]

JOLT Keep structure after array shift

I'm trying to construct a JOLT transformation such that it will change a parameter value if the paramter name matches in a given array.
Example Input:
{
"component": {
"parameters": [
{
"parameter": {
"name": "var_name",
"value": "val"
}
},
{
"parameter": {
"name": "1",
"value": "2"
}
}
]
},
"additional": "onemore"
}
Desired Output:
{
"component": {
"parameters": [
{
"parameter": {
"name": "var_name",
"value": "new_val"
}
},
{
"parameter": {
"name": "1",
"value": "2"
}
}
]
},
"additional": "onemore"
}
My Current JOLT transform:
[
{
"operation": "shift",
"spec": {
"component": {
"parameters": {
"*": {
"parameter": {
"name": {
"var_name": {
"#new_val": "&6.&5[&4].&3.value"
}
}
}
}
}
}
}
}
]
The problem with my JOLT transform is that it deletes the rest of the Json, whereas I'd like to mantain it unchanged if there's no match
I tried looking for a solution, but the closest I got was this one, which allowed me to make the current transform, but I don't understand how to fix it properly.
EDIT:
I actually missed part of the input when writing the example, but thanks to #Barbaros Özhan answer I was able to complete my transformation.
For future rference if anybody else needs it my original input had additonal fields like:
{
"component": {
"parameters": [
{
"option": "true",
"parameter": {
"name": "var_name",
"description": "desc",
"value": "val"
}
},
{
"option": "false",
"parameter": {
"name": "1",
"description": "desc",
"value": "2"
}
}
],
"other value": "baz"
},
"additional": "onemore"
}
And the final transformation I used was slightly tweaked to account for those like so:
[
{
"operation": "shift",
"spec": {
"component": {
"parameters": {
"*": {
"parameter": {
"name": {
"#": "&5.&4[&3].&2.&1",
"var_name": {
"#new_val": "&6.&5[&4].&3.value"
},
"*": {
"#(2,value)": "&6.&5[&4].&3.value"
}
},
"value": "&6.&5[&4].&3.value",
"*": "&4.&3[&2].&1.&"
},
"*": "&3.&2[&1].&"
}
},
"*": "&1.&"
},
"*": "&"
}
}
]
You can use this shift transformation spec
[
{
"operation": "shift",
"spec": {
"component": {
"parameters": {
"*": {
"parameter": {
"name": {
"#": "&5.&4[&3].&2.&1", // # matches the value taken from one level up, eg. replicating "name"
"var_name": {
"#new_val": "&6.&5[&4].&3.value"
},
"*": {
"#(2,value)": "&6.&5[&4].&3.value"
}
}
}
}
}
},
"*": "&" // the "else" case(the attributes other than "component")
}
}
]

Jolt spec to transform fields in selective objects

For my input json, I need to write a Jolt spec that can modify manager attribute by joining the value & position fields in only the user type object and not the other object type account.
The input could be a list of such objects.
Input:
[
{
"user": {
"userName": "Mike",
"manager": {
"value": "Harvey",
"position": "Director"
}
},
"account": {
"userLogin": "Mike1987",
"status": true
}
},
{
"user": {
"userName": "Alex",
"manager": {
"value": "Daniel",
"position": "President"
}
},
"account": {
"userLogin": "Alex12a",
"status": true
}
}
]
Desired output:
[
{
"user": {
"userName": "Mike",
"managerRef": {
"info": "Harvey_Director"
}
},
"account": {
"userLogin": "Mike1987",
"status": true
}
},
{
"user": {
"userName": "Alex",
"managerRef": {
"info": "Daniel_President"
}
},
"account": {
"userLogin": "Alex12a",
"status": true
}
}
]
Could someone please help in creating the spec for this transformation. Thanks.
You can use a modify transformation spec which contains a concat function such as
[
{
"operation": "modify-overwrite-beta",
"spec": {
"*": {
"user": {
"manager": {
"info": "=concat(#(1,value),'_',#(1,position))"
}
}
}
}
},
{
// get rid of existing attributes within the object
"operation": "remove",
"spec": {
"*": {
"u*": {
"m*": {
"p*|v*": ""
}
}
}
}
}
]
the demo on the site http://jolt-demo.appspot.com/ is
An alternative method which includes a shift transformation as desired, based on the comment would be
[
{
"operation": "shift",
"spec": {
"*": {
"user": {
"*": "[&2].&1.&",
"manager": {
"*": "[&3].&2.&1.info"
}
},
"*": "[&1].&"
}
}
},
{
"operation": "modify-overwrite-beta",
"spec": {
"*": {
"user": {
"manager": {
"info": "=join('_',#(1,&))"
}
}
}
}
}
]
the demo for this case would be :

Jolt transformation array data

I want to transform a JSON using JOLT like this:
Input: {
"array": [
"1","2","3","4"
],
"array2": [
{
"something": "123",
"something1": "Plane"
},
{
"something3": "567",
"something4": "Car"
}
]
}
Into the following format, as you can see from output I need data from both arrays to fit exact param names, not empty one like in the first or existed param names like in the second one.
Output: {
"one_array": [
{
"code": "1",
"description": "",
},
{
"code": "2",
"description": "",
},
{
"code": "3",
"description": "",
},
{
"code": "4",
"description": "",
}
], "other_array": [
{
"id": "123",
"type": "Plane"
},
{
"id": "567",
"type": "Car"
}
]
}
Some clarifications are really appreciated
You can achieve this using 2 shift operations and the default operation as below.
[
{
"operation": "shift",
"spec": {
"array": {
"*": {
"#": "one_array[&].id"
}
},
"array2": {
"*": {
"*": {
"#": "tmp_array[&2]"
}
}
}
}
},
{
"operation": "shift",
"spec": {
"one_array": "one_array",
"tmp_array": {
"*": {
"0": "other_array[&1].id",
"1": "other_array[&1].type"
}
}
}
},
{
"operation": "default",
"spec": {
"one_array[]": {
"*": {
"description": ""
}
}
}
}
]