How to condense a json object based on a key in dataweave - mule

I have a json structure as follows:
[
{
"apiId": 18211158,
"policyName0": "cors"
},
{
"apiId": 18211158,
"policyName1": "client-id-enforcement"
},
{
"apiId": 18211150,
"policyName0": "client-id-enforcement"
},
{
"apiId": 18211162,
"policyName0": "client-id-enforcement"
},
{
"apiId": 18211162,
"policyName1": "cors"
},
{
"apiId": 18211162,
"policyName2": "oauth"
}
]
I need to transform this into following using dataweave 2.0
[
{
"apiId": 18211158
"policyName0": "cors",
"policyName1": "client-id-enforcement",
},
{
"apiId": 18211150
"policyName0": "client-id-enforcement",
},
{
"apiId": 18211162
"policyName0": "client-id-enforcement",
"policyName1": "cors",
"policyName2": "oAuth",
}
]
Note that each apiID can have multiple policies and the policyName json attribute is generated and cal have values ranging from 1 to 9.
How can I condense the json based on apiID as the key in dataweave?

The best way to do this is by using a groupBy with a pluck to reshape the groups into objects
%dw 2.0
output application/json
---
payload
groupBy ((value, key) -> value.apiId)
pluck ((value, key, index) -> {
"apiId": key,
(value map ((item, index) -> item - "apiId"))
})

Try the below code
%dw 2.0
output application/json skipNullOn="everywhere"
---
payload groupBy $."apiId" pluck $ map {
apiId: $."apiId"[0],
policyName0: $.policyName0[0],
policyName1: $.policyName1[0],
policyName1: $.policyName2[0]
}
Output As below
[
{
"apiId": 18211158,
"policyName0": "cors",
"policyName1": "client-id-enforcement"
},
{
"apiId": 18211150,
"policyName0": "client-id-enforcement"
},
{
"apiId": 18211162,
"policyName0": "client-id-enforcement",
"policyName1": "cors",
"policyName1": "oauth"
}
]

Related

Mule Nested JSON data issue - If Child does not exists in data mule output parent and child columns data NULL

Mule Nested JSON data issue - If Child does not exists in data mule output parent and child columns data NULL. How to capture parent columns data if child data not exists.
JSON Data :
{
"Report_Entry": [{
"p_sname": "TEST_1",
"p_sno": "1234",
"SUBJECT_DATA_GROUP": [
{
"sub_name": "social",
"sub_marks: "80"
},
{
"sub_name": "science",
"sub_marks: "60"
},
{
"sub_name": "maths",
"sub_marks: "90"
}
],
"p_s_start_date": "10-10-1991",
"p_s_status": "A"
},
{
"p_sname": "TEST_2",
"p_sno": "9999",
"SUBJECT_DATA_GROUP": [
{
"sub_name": "social",
"sub_marks: "30"
},
{
"sub_name": "science",
"sub_marks: "40"
},
{
"sub_name": "maths",
"sub_marks: "50"
}
],
"p_s_start_date": "10-10-1999",
"p_s_status": "A"
},
{
"p_sname": "TEST_3",
"p_sno": "8888",
"p_s_start_date": "10-10-2000",
"p_s_status": "A"
},
{
"p_sname": "TEST_4",
"p_sno": "6666",
"p_s_start_date": "10-10-2020",
"p_s_status": "A"
}
]
}
%dw 2.0
output application/java
---
payload.Report_Entry flatMap ((item, order) ->
item.SUBJECT_DATA_GROUP map ((line, lineOrder) -> {
//Main
"p_sname": item.p_sname,
"p_sno": item.p_sno,
"Hours": item.Hours,
//Line
"sub_name": line.sub_name,
"sub_marks": line.sub_marks,
//Main
"p_s_start_date": item.p_s_start_date,
"p_s_status": item.p_s_status
}
)
)
Result :
p_sname|p_sno|sub_name|sub_marks|p_s_start_date|p_s_status
TEST_1|1234|social|80|10-10-1991|A
TEST_1|1234|science|60|10-10-1991|A
TEST_1|1234|maths|90|10-10-1991|A
TEST_2|9999|maths|30|10-10-1999|A
TEST_2|9999|maths|40|10-10-1999|A
TEST_2|9999|maths|50|10-10-1999|A
null|null|null|null|null|null
null|null|||null|null
Expected Result :
p_sname|p_sno|sub_name|sub_marks|p_s_start_date|p_s_status
TEST_1|1234|social|80|10-10-1991|A
TEST_1|1234|science|60|10-10-1991|A
TEST_1|1234|maths|90|10-10-1991|A
TEST_2|9999|maths|30|10-10-1999|A
TEST_2|9999|maths|40|10-10-1999|A
TEST_2|9999|maths|50|10-10-1999|A
TEST_3|8888|||10-10-2000|A
TEST_4|6666|||10-10-2020|A
You can use default keyword to set array with an empty object to handle scenarios where SUBJECT_DATA_GROUP doesn't exists.
I have used application/csv as the mimetype to match the given output.
%dw 2.0
output application/csv separator="|"
---
payload.Report_Entry flatMap ((item) ->
item.SUBJECT_DATA_GROUP default [{}] map ((line) -> {
p_sname: item.p_sname,
p_sno: item.p_sno,
Hours: item.Hours,
sub_name: line.sub_name,
sub_marks: line.sub_marks,
p_s_start_date: item.p_s_start_date,
p_s_status: item.p_s_status
})
)

Extract the inner field objects and apply them to respective top level objects using Dataweave2.0

I am trying to achieve the below output from the given input. I have tried several ways of making a generic function so that when any data is passed with similar structure I get the similar output. Please help me to achieve this.
Input
[{
"name": "Thinker",
"details": [
{
"num": 1
},
{
"num": 2
}
]
},
{
"name": "Blinker",
"details": [
{
"num": 3
},
{
"num": 4
}
]
}]
Output
[{
"name": "Thinker",
"num": 1
},
{
"name": "Thinker",
"num": 2
},
{
"name": "Blinker",
"num": 3
},
{
"name": "Blinker",
"num": 4
}]
The key is mapping through both outer and inner arrays and then flattening the result:
output application/json
---
flatten (payload map ((item, index) -> item.details map ((detail, index) -> {
name: item.name,
num: detail.num
})))
As Aled has mentioned in his comments to one of the answers, this could be another way to solve this.
%dw 2.0
output application/json
---
payload flatMap (item,index) -> (
item.details map {
name: item.name,
num: $.num
}
)
Try this DW
1st Map to Map on main array
2nd Map to Map on details
reduce to convert nested array to single array
%dw 2.0
output application/json
---
payload map(
($.details map(item,index)->{
"name":($.name),
"num":item[0]
})
)reduce($$++$)
Output
[
{
"name": "Thinker",
"num": 1
},
{
"name": "Thinker",
"num": 2
},
{
"name": "Blinker",
"num": 3
},
{
"name": "Blinker",
"num": 4
}
]
DW
%dw 2.0
output application/json
---
payload map(
($.details map(item,index)->{
(keysOf($)[0]):($.name),
(keysOf(item)[0]):item[0]
})
)reduce($$++$)
If your request structure will always remain this way(regardelss of field names), then you can try this script as below, that is more genric and will work on same type of strucure
%dw 2.0
output application/json
---
payload flatMap ((item, index) ->
(item filterObject ($ is Array))[0] map
($ ++ (item filterObject ($ is String | Number | Null)) )
)
Note: it can work on this type of structure always and not depend on field names, and gives expected output
[{
"anyname": "xyz",
"anydetails": [
{
"abc": 1
},
{
"ijk": 2
}
]
}]

Convert properties from properties file into json in Dataweave 2.0

How to convert properties from a properties file
creditmaster.metadata.AverageFicoScore=700
creditmaster.a.b.c=xyz
into this json format in a generic way
{
creditmasterMetaData: [
{
attributeKey: "AverageFicoScore",
attributeValue: 700
}
]
}
This script is generic in that it doesn't matter what are the parts of the key, it only groups by the first element (before of the first dot) and the key name after the last dot, it ignores everything in the middle:
%dw 2.3
output application/java
import * from dw::core::Strings
fun mapProperties(props) =
entriesOf(props) // since Mule 4.3 / DW 2.3
filter (substringAfter($.key, ".") startsWith "metadata.") // to filter keys with .metadata.
groupBy ((item, index) -> substringBefore(item.key, "."))
mapObject ((value, key, index) ->
(key): value map {
attributeKey: substringAfterLast($.key, "."),
attributeValue: if (isInteger($.value)) $.value as Number else $.value
}
)
---
mapProperties(payload)
Input file:
creditmaster.metadata.AverageFicoScore= 700
other.a.b= 123
creditmaster.a.b.c=xyz
something.metadata.another.maximum=456
creditmaster.metadata.different.minimum=500
Output (in JSON for clarity):
{
"something": [
{
"attributeKey": "maximum",
"attributeValue": "456"
}
],
"creditmaster": [
{
"attributeKey": "minimum",
"attributeValue": "500"
},
{
"attributeKey": "AverageFicoScore",
"attributeValue": "700"
}
]
}
One alternative is using the pluck function. It lets you iterate over an object receiving the entries.
If you have this input
{
"creditmaster": {
"metadata": {
"AverageFicoScore": "700",
"OtherData": "Some value"
}
}
}
with this transformation
{
creditmasterMetaData:
payload.creditmaster.metadata pluck ((value, key, index) ->
{
attributeKey: key,
attributeValue: value
}
)
}
you get this output
{
"creditmasterMetaData": [
{
"attributeKey": "AverageFicoScore",
"attributeValue": "700"
},
{
"attributeKey": "OtherData",
"attributeValue": "Some value"
}
]
}

Transformation of JSON data in mule 4

I have a requirement wherein I have to convert JSON data from one format to other.
I have to fetch corresponding values of JSON array and make them a key value pair.
Below are the required details:
Input:
"Headers": {
"Header": [
{
"Key": "SellerOrganization",
"Value": "XYZ"
},
{
"Key": "SellerType",
"Value": "B2C"
},
{
"Key": "Region",
"Value": "SOUTH"
},
{
"Key": "OrderType",
"Value": "RETURN"
},
{
"Key": "InvoiceType",
"Value": ""
},
{
"Key": "EventType",
"Value": "Created"
},
{
"Key": "EntryType",
"Value": "Call Center"
}
]
}
Expected Output:
{
SellerOrganization:XYZ,
SellerType: B2C,
Region:SOUTH,
OrderType:RETURN,
InvoiceType:"",
EventType:Created,
EntryType:Call Center
}
You can use the dynamic object that it will basically do what you want.
%dw 2.0
output application/json
---
{
(payload.Headers.Header map ((item, index) -> {
(item.Key): item.Value
})
)
}
You can take advantage of reduce function here which will let you convert your array to an key, value pair object
%dw 2.0
output application/json
---
payload.Header reduce ((item, acc = {}) -> acc ++ {
(item.Key): item.Value
})

Creating a single json from a combined json list

I am getting multiple json files in a for loop and each json in each loop are in a format :
{
"myproperties": {
"http.port": "8088",
"http.base": "/abc",
"http.path": "test"
},
"information": [{
"abc": {
"key1": "ghghghghgh"
},
"efg": {
"key1": "value1"
}
}]
}
and
{
"myproperties": {
"http.port": "6789",
"db.base": "tat",
"db.path": "ghghghg"
},
"information": [{
"efg": {
"key1": "ghghghghgh"
},
"ijk": {
"key1": "value1"
}
}]
}
and so on ……….
I manage to combine all the json in a list out side the for loop and the combine json list looks like:
[{
"myproperties": {
"http.port": "8088",
"http.base": "/abc",
"http.path": "test"
},
"information": [{
"abc": {
"key1": "ghghghghgh"
},
"efg": {
"key1": "value1"
}
}]
},
{
"myproperties": {
"http.port": "6789",
"db.base": "tat",
"db.path": "ghghghg"
},
"information": [{
"efg": {
"key1": "ghghghghgh"
},
"ijk": {
"key1": "value1"
}
}]
}]
Now I want to make **single** json output out of this combine json something in a following format:
{
"myproperties": {
"http.port": "6789",
"db.base": "tat",
"db.path": "ghghghg",
"http.base": "/abc",
"http.path": "test"
},
"information": [{
"efg": {
"key1": "ghghghghgh"
},
"ijk": {
"key1": "value1"
}
},
{
"abc": {
"key1": "ghghghghgh"
},
"efg": {
"key1": "value1"
}
}
]
}
please note in the myproperties section only unique and distinct node is there.
I am not sure how to begin this with dataweave… any pointer will be appreciated,
I tried the following :
%dw 1.0
%output application/json skipNullOn="everywhere",encoding="UTF-8"
---
payload map {
myproperties: $.myproperties,
information: $.information
}
But not working
Thanks
Try mapObject for combining properties and flatten for changing information array to single array like
%dw 1.0
%output application/json
---
{
myproperties : payload.myproperties mapObject $ ,
information : (flatten payload.information)
}
HTH
Update:-
For distinct properties you have to get distinct properties first and then map all distinct properties. But you may loose duplicate properties. refer below
%dw 1.0
%output application/json
%var distinctProperties =((payload.myproperties mapObject $) pluck $$) distinctBy $
%var aggregatedPropertiesMap = (payload.myproperties mapObject $)
---
{
myproperties : {( distinctProperties map { // interate over distinct properties
($) : aggregatedPropertiesMap[$] // map property as key and fetch its value from aggregatedPropertiesMap
})} ,
information : (flatten payload.information)
}