Add array inside object with same key in jolt spec - jolt

I would like to move the recommendations array by row_id key inside the investors with the same row_id
Original Json
{
"investors": [
{
"row_id": 1,
"name": "AAAA"
},
{
"row_id": 2,
"name": "BBBB"
}
],
"recommendations": [
{
"row_id": "1",
"title": "ABC"
},
{
"row_id": "2",
"title": "CDE"
}
]
}
I've tried a lot of specs at https://jolt-demo.appspot.com with no success
Specs tried...
[{
"operation": "shift",
"spec": {
"investors": {
"*": "investors[]"
},
"recommendations": {
"#": "recommendations[]"
}
}
}]
Desired Json
{
"investors": [
{
"row_id": 1,
"name": "AAAA",
"recommendations":[{
"row_id": "1",
"title": "ABC"
}]
},
{
"row_id": 2,
"name": "BBBB",
"recommendations":[{
"row_id": "2",
"title": "CDE"
}]
}
]
}

This can be done in two stage shift
First shift groups everything based on row_id.
(I'd suggest running the first shift of its own to see what the output is)
Second shift uses that grouped output and formats results.
[
{
"operation": "shift",
"spec": {
"*": {
"*": {
"row_id": {
"*": {
"#2": "&.&4"
}
}
}
}
}
},
{
"operation": "shift",
"spec": {
"*": {
"investors": "investors.[#2]",
"recommendations": "investors.[#2].recommendations[]"
}
}
}
]

Related

Facing issue with JOLT transformation with nested array

I have a JSON input :
{
"id": "Root_ID",
"Item": [
{
"id": "ID_1",
"characteristic": [
{
"name": "char1",
"value": "PRE1"
},
{
"name": "char2",
"value": "2050-01-01"
}
]
},
{
"id": "ID_2",
"characteristic": [
{
"name": "char1",
"value": "PRE2"
},
{
"name": "char2",
"value": "2050-01-02"
}
]
}
]
}
which needs to be converted by using a Jolt transformation spec to the following output :
{
"id": "Root_ID",
"Item": [
{
"id": "ID_1",
"char1": "PRE1",
"char2": "2050-01-01"
},
{
"id": "ID_2",
"char1": "PRE2",
"char2": "2050-01-02"
}
]
}
Currently, I'm using this spec :
[
{
"operation": "shift",
"spec": {
"id": "id",
"Item": {
"*": {
"characteristic": {
"*": {
"name": {
"char1": {
"#(2,value)": "item[#3].char1"
},
"char2": {
"#(2,value)": "item[#3].char2"
}
}
}
}
}
}
}
}
]
which does not produce the desired result.
Can you please help me prepare a correct spec to handle this issue ?
Edit : What if I'd like to get the following JSON result ?
{
"id": "Root_ID",
"Item": [
{
"id": "ID_1",
"char1": "PRE1"
},
{
"id": "ID_2",
"char1": "PRE2",
"char2": "2050-01-02"
}
]
}
You can use the following shift transformation spec in which #value and #name are matched reciprocally such as
[
{
"operation": "shift",
"spec": {
"id": "&",
"Item": {
"*": {
"id": "&2[&1].&",// you can reduce two levels based on the inner identifier 4,3 -> 2,1
"char*": {
"*": {
"#value": "&4[&3].#name" // &4 copies the literal "Item" after going four levels up the tree, [&3] generates array-wise result(array of objects) after going three levels up the tree to reach the level of the indexes of the "Item" array
}
}
}
}
}
}
]
Edit : You can alternatively use the following spec for the case in which you need to return char2 within the all objects but the first :
[
{
"operation": "shift",
"spec": {
"id": "&",
"Item": {
"0": {// stands for the first index
"id": "&2[&1].&",
"char*": {
"*": {
"name": {
"char1": {
"#2,value": "&6[&5].#3,name"
}
}
}
}
},
"*": {
"id": "&2[&1].&",
"char*": {
"*": {
"#value": "&4[&3].#name"
}
}
}
}
}
}
]

Jolt : Add key in sub object

Input
{
"id": 1,
"name": "Sample name",
"attributes": {
"age": 10
}
}
Output
{
"id": 1,
"attributes": {
"name": "Sample name",
"age": 10
}
}
I want to carry out this transformation. I tried with the below spec
[
{
"operation": "shift",
"spec": {
"*": "&",
"name": "attributes.&"
}
}
]
But this changes attributes field into an array. What should be the right spec used here?
The following spec would work
[
{
"operation": "shift",
"spec": {
"*": "&",
"name": "attributes.&",
"attributes": {
"*": "attributes.&"
}
}
}
]

JOLT Nested if condition

I have this input JSON:
{
"user": "123456",
"product": "television",
"category": "electronics",
"tag": "summer"
}
And this transformation:
[
{
"operation": "shift",
"spec": {
"product": {
"#(1,product)": "item",
"#(1,user)": {
"#2": "userBias"
}
},
"user": {
"#(1,user)": "user"
},
"category": {
"#category": "rules.[0].name",
"#(1,category)": "rules.[0].values[0]"
},
"tag": {
"rules": "rules",
"#tag": "rules.[1].name",
"#(2,tag)": "rules.[1].values[0]"
}
}
},
{
"operation": "modify-overwrite-beta",
"spec": {
"userBias?": "=toInteger"
}
}
]
Which works fine and produces the following JSON:
{
"item": "television",
"userBias": 2,
"user": "123456",
"rules": [
{
"name": "category",
"values": [
"electronics"
]
},
{
"name": "tag",
"values": [
"summer"
]
}
]
}
If from the input though I delete "category": "electronics" so it becomes:
{
"user": "123456",
"product": "television",
"tag": "summer"
}
Then i get back the following result:
{
"item": "television",
"userBias": 2,
"user": "123456",
"rules": [
null,
{
"name": "tag",
"values": [
"summer"
]
}
]
}
The problem with the above is that it contains a null element inside the array and I do not know how to get rid of it. I have tried with recursivelySquashNulls but it does not work.
Also basically what am looking for is if both category and tag exist then tag should go to rules[1] if only tag exists then tag should go to rules[0].
Thanks in advance,
giannis
Because you specify tag and category elements individually. Rather, prefer putting them into the category rest by combining them under asterisked key notation such as
[
{
"operation": "shift",
"spec": {
"product": {
"#(1,product)": "item",
"#(1,user)": {
"#2": "userBias"
}
},
"user": {
"#(1,user)": "user"
},
"*": {
"$": "r[0].&.name",
"#(1,&)": "r[0].&.values[]"
}
}
},
{
"operation": "shift",
"spec": {
"*": "&",
"r": {
"*": { "*": "rules" }
}
}
},
{
"operation": "modify-overwrite-beta",
"spec": {
"userBias?": "=toInteger"
}
}
]
Result1 :
Result2(without "category": "electronics" pair for the Input) :

Jolt grouping together and including new tags

I have the following input JSON and want to group the sub jsons according to device name.(Device name has to be extracted from address). Also, i want to add new tags to the new arrays formed(Each array contains jsons having that type of device name only).
I've already tried below spec but the array Name name is appearing as deviceName instead of custom Parameter(I don't know how to provide custom name. for example i want the array name as "Parameters"). I'm not able to extract the device name from address field.(Device Name should come as "bee"/"honey"). Also, I want to add a new field which should be there once for the new array (and not for each element).
Input Json:
{
"CID": "AND",
"parameters": [{
"address": "abc:api:honey",
"name": "CH1"
},
{
"address": "abc:api:honey",
"name": "CH2"
},
{
"address": "abc:api:bee",
"name": "lat"
},
{
"address": "abc:api:bee",
"name": "long"
}
],
"rNo": 1232
}
Expected Output:
[{
"ID": "AND_1232",
"parameters": [{
"deviceName": "honey",
"name": "CH1",
"locoId": 1232,
"CID": "AND"
},
{
"deviceName": "honey",
"name": "CH2",
"locoId": 1232,
"CID": "AND"
}
],
"SpData": {
}
},
{
"ID": "AND_1232",
"parameters": [{
"deviceName": "bee",
"name": "lat",
"locoId": 1232,
"CID": "AND"
},
{
"deviceName": "bee",
"name": "long",
"locoId": 1232,
"CID": "AND"
}
],
"SpData": {
}
}]
Spec I tried:
[
{
"operation": "shift",
"spec": {
"parameters": {
"*": {
"#(2,CID)": "&2.[&1].CID",
"*": "&2.[&1].&",
"#(2,rNo)": "&2.[&1].locoId"
}
}
}
},
{
"operation": "modify-overwrite-beta",
"spec": {
"ID": "=concat(#(0,CID),'_',#(0,rNo))",
"parameters": {
"*": {
"deviceName": "=substring(#(1,address),8,11)",
"SpData": {}
}
}
}
}, {
"operation": "shift",
"spec": {
"parameters": {
"*": {
"deviceName": {
"*": {
"#2": "&[]"
}
}
}
}
}
}
]
The following will output desired results, each operation does the following respectively:
Add ID by concatenating CID and rNo
Add rNo and CID to all parameters and add deviceName (see here for details on device name splitting).
Group records by deviceName using object
Add ID to each group
Convert temporary grouping to array
Add default SpData
[
{
"operation": "modify-default-beta",
"spec": {
"ID": "=concat(#(1,CID),'_',#(1,rNo))"
}
},
{
"operation": "shift",
"spec": {
"ID": "&",
"parameters": {
"*": {
"address": {
"*:*:*": {
"$(0,3)": "parameters.[&3].deviceName"
}
},
"#(0,name)": "parameters.[&].name",
"#(2,rNo)": "parameters.[&].locoId",
"#(2,CID)": "parameters.[&].CID"
}
}
}
},
{
"operation": "shift",
"spec": {
"ID": "&",
"parameters": {
"*": {
"deviceName": {
"*": {
"#(3,[&2])": "tmp.&.parameters.[]"
}
}
}
}
}
},
{
"operation": "shift",
"spec": {
"tmp": {
"*": {
"#(2,ID)": "&1.ID",
"parameters": {
"#": "&2.parameters"
}
}
}
}
},
{
"operation": "shift",
"spec": {
"*": "[]"
}
},
{
"operation": "default",
"spec": {
"*": {
"SpData": {}
}
}
}
]

Combining two arrays and transformation using Jolt

I am having a tough time using Jolt mapping trying to transform the input to the necessary form
Input JSON
{
"data": [
{
"name": "Alcohol",
"collection_id": 123,
"properties": [
{
"name": "Tax",
"property_id": "00001"
},
{
"name": "Expenditure",
"property_id": "00002"
}
],
"attributes": [
{
"name": "alcohol_tax",
"attribute_id": "00011"
},
{
"name": "alcohol_expenditure",
"attribute_id": "00022"
}
]
}
]
}
Output JSON
[
{
"name": "Alcohol",
"collection_id": 123,
"details": [{
"property_name": "Tax",
"property_id": "00001",
"attribute_id": "00011"
},
{
"property_name": "Expenditure",
"property_id": "00002",
"attribute_id": "00022"
}
]
}
]
I have tried a couple of ways to combine the arrays using a few rules but with little success.
One of the rules
[{
"operation": "shift",
"spec": {
"data": {
"*": {
"name": "&1.name",
"collection_id": "&1.collection_id",
"attributes": {
"*": {
"attribute_id": "&1.attribute_id[]"
}
},
"properties": {
"*": {
"name": "&1.myname[]",
"property_id": "&1.property_id[]"
}
}
}
}
}
}]
is adding all the attributes and properties to all the collections.I do not know why this happens as I thought &1.property_id[] would only add items in that particular collection to the array and not all collections. Any help/clues on why this is happening would be truly appreciated.
See solution below:
[0] creates the wrapping array
[&1] uses the position of the respective arrays so the results are combined in details the important part is wrapping square brackets so its treated as array rather than literal.
[
{
"operation": "shift",
"spec": {
"data": {
"*": {
"name": "[0].name",
"collection_id": "[0].collection_id",
"attributes": {
"*": {
"attribute_id": "[0].details.[&1].attribute_id"
}
},
"properties": {
"*": {
"name": "[0].details.[&1].name",
"property_id": "[0].details.[&1].property_id"
}
}
}
}
}
}
]
Produces the following:
[
{
"name": "Alcohol",
"collection_id": 123,
"details": [
{
"attribute_id": "00011",
"name": "Tax",
"property_id": "00001"
},
{
"attribute_id": "00022",
"name": "Expenditure",
"property_id": "00002"
}
]
}
]