Mulesoft DataWeave: Transform flat list - mule

I am relatively new to DataWeave, and was wondering how/if I can transform a message like below using DataWeave instead of a Java transformer.
If I have the following JSON payload of users, with a group and subgroup:
[{
"GROUP": "GROUP_A",
"SUBGROUP": "SUBGROUP A1",
"USER": "USER 1"
}, {
"GROUP": "GROUP_B",
"SUBGROUP": "SUBGROUP B1",
"USER": "USER 1"
}, {
"GROUP": "GROUP_B",
"SUBGROUP": "SUBGROUP B1",
"USER": "USER 2"
}, {
"GROUP": "GROUP_B",
"SUBGROUP": "SUBGROUP B2",
"USER": "USER 3"
}, {
"GROUP": "GROUP_B",
"SUBGROUP": "SUBGROUP B2",
"USER": "USER 4"
}, {
"GROUP": "GROUP_B",
"SUBGROUP": "SUBGROUP B2",
"USER": "USER 5"
}]
What would a DataWeave transformation look like to tranform the payload to something structured like the following:
[
{
"GROUP": "GROUP_A",
"SUBGROUPS": [{
"NAME": "SUBGROUP A1",
"USERS": ["USER 1"]
}]
}, {
"GROUP": "GROUP_B",
"SUBGROUPS": [{
"NAME": "SUBGROUP B1",
"USERS": ["USER 1", "USER 2"]
}, {
"NAME": "SUBGROUP B2",
"USERS": ["USER 3", "USER 4", "USER 5"]
}]
}
]
Thanks for any help!

For DataWeave development, please refer to DataWeave Reference Documentation. At this case You can refer to section Group by …. To transform above message, then try this script:
%dw 1.0
%output application/json
---
payload groupBy $.GROUP pluck {
GROUP: $$,
SUBGROUPS: $ groupBy $.SUBGROUP pluck {
NAME: $$,
USERS: $.USER
}
}

Related

Compare the inputs and get the response?

Input 01:
{
"labelItems": [{
"label": "manager",
"role": "MA"
}, {
"label": "Developer",
"role": "DEV"
}]
}
Input 02:
{
"List": [{
"id": "M123",
"label": "Manager"
},
{
"id": "L240",
"label": "Lead"
},
{
"id": "D250",
"label": "Developer"
}
]
}
Final output:
{
"Labels": [{
"id": "M123",
"role": "MA"
},
{
"id": "D250",
"role": "DEV"
}
]
}
Can anyone provide me the above desired final output response, we have two input payloads and compare two payloads with the label field and get the id & role fields from the array of the list.
Thanks in Advance,
One way would be to iterate on Input 02 ( I have set Input 01 as the payload to this script) and pass over the label to filter the payload, to procure the corresponding role. Have used capitalize since the manager in payload (Input 01) starts with lowercase m while the same starts with Uppercase m in Input 02 label for id M123.
%dw 2.0
output application/json
import * from dw::core::Strings
var inp2 = {
"List": [{
"id": "M123",
"label": "Manager"
},
{
"id": "L240",
"label": "Lead"
},
{
"id": "D250",
"label": "Developer"
}
]
}
---
Labels: inp2.List map ((item, index) -> {
id: item.id,
role: (payload.labelItems filter (capitalize($.label) == item.label )).'role'[0]
}) filter (!($.role == null))
Another modification to this could be:
%dw 2.0
output application/json
import * from dw::core::Strings
var inp2 = {
"List": [{
"id": "M123",
"label": "Manager"
},
{
"id": "L240",
"label": "Lead"
},
{
"id": "D250",
"label": "Developer"
}
]
}
var interim = payload.labelItems map {
(capitalize($.label)): $.role
}
---
Labels: inp2.List map ((item, index) -> {
id: item.id,
role: interim[(item.label)][0]
}) filter (!($.role == null))
Another way to do this is by using joins. I have used leftJoin for joining the arrays.
%dw 2.0
import * from dw::core::Arrays
output application/json
var inp2 = {
"List": [{
"id": "M123",
"label": "Manager"
},
{
"id": "L240",
"label": "Lead"
},
{
"id": "D250",
"label": "Developer"
}
]
}
---
Labels: leftJoin (payload.labelItems, inp2.List,
(labelItems)-> lower(labelItems.label), (listItems) -> lower(listItems.label))
map {
id: $.r.id,
role: $.l.role
}
You can iterate over input 1 and compare the current item's label with label in in2's list to get the corresponding id
%dw 2.0
output application/json
var in1={
"labelItems": [{
"label": "manager",
"role": "MA"
}, {
"label": "Developer",
"role": "DEV"
}]
}
var in2={
"List": [{
"id": "M123",
"label": "Manager"
},
{
"id": "L240",
"label": "Lead"
},
{
"id": "D250",
"label": "Developer"
}
]
}
---
Labels: in1.labelItems default [] map (item, index) -> {
id: in2.List[?(lower($.label) == lower(item.label))][0].id,
role: item.role
}
Have used lower to avoid any case sensitivity

How to map an array within an array and achieve the following output?

In the given input,
{
"editable": true,
"sections": [
{
"title": "Identification",
"calingaKey": "",
"content": [
[{
"name": "Classification",
"text": "Product",
"url": "",
"info": ""
},
{
"name": "Product Number",
"text": "####1234",
"url": "",
"info": ""
}]
]
},
{
"title": "Position and Contact",
"calingaKey": "",
"content": [
[{
"name": "Manufacturer",
"text": "Value of Manufacturer",
"url": "",
"info": ""
},
{
"name": "Hardware Version",
"text": "####1234",
"url": "",
"info": ""
}]
]
}
]
}
"content" is an array of array of objects. Basically, the "name" field has to be replaced by values stored in their corresponding keys in the "calinga" variable.
I could do it for the "title" field, but each "name" field should also be replaced by it's name in the variable.
%dw 2.0
output application/json
var calinga = {
"Identification": "Identifikation",
"Position and Contact": "Positions und Contacts",
"Classification": "Classifikation",
"Product Number": "Produkt Number",
"Manufacturer": "Manufakturer",
"Hardware Version": "Hware Vsion"
}
---
{
"editable": payload.editable,
"sections": payload.sections map(item01, index01)->{
"title": calinga[item01.title],
"content": item01.content map(item02)->(item02)
}
}
How Can I achieve the following output?
{
"editable": true,
"sections": [
{
"title": "Identifikation",
"calingaKey": "",
"content": [
[{
"name": "Classifikation",
"text": "Product",
"url": "",
"info": ""
},
{
"name": "Produkt Number",
"text": "####1234",
"url": "",
"info": ""
}]
]
},
{
"title": "Positions und Contacts",
"calingaKey": "",
"content": [
[{
"name": "Manufakturer",
"text": "Value of Manufacturer",
"url": "",
"info": ""
},
{
"name": "Hware Vsion",
"text": "####1234",
"url": "",
"info": ""
}]
]
}
]
}
You can use mapObject() once you descend from the last nested array into objects. Then the trick is to use the value of calinga but if it null because the key is not present then use the original value as the default: item03 mapObject {($$):calinga[$] default $}.
Example:
%dw 2.0
output application/json
var calinga = {
"Identification": "Identifikation",
"Position and Contact": "Positions und Contacts",
"Classification": "Classifikation",
"Product Number": "Produkt Number",
"Manufacturer": "Manufakturer",
"Hardware Version": "Hware Vsion"
}
---
{
"editable": payload.editable,
"sections": payload.sections map(item01, index01)->{
"title": calinga[item01.title],
"content": item01.content map(item02)->(item02 map(item03)-> item03 mapObject {($$):calinga[$] default $})
}
}

Dynamically trying to update a field in an object using dataweave, how to achieve the same?

The use case is : we'll be having translations stored in an object in a variable in the dataweave, we have to dynamically assign those translations in the "calingaKey" value, I tried doing something below, but it isn't working.
Input
{
"editable": true,
"sections": [
{
"title": "Identification",
"calingaKey": "",
"content": [
{
"name": "Classification",
"text": "Product",
"url": "",
"info": ""
},
{
"name": "Product Number",
"text": "####1234",
"url": "",
"info": ""
}
]
},
{
"title": "Position and Contact",
"calingaKey": "",
"content": [
{
"name": "Manufacturer",
"text": "Value of Manufacturer",
"url": "",
"info": ""
},
{
"name": "Hardware Version",
"text": "####1234",
"url": "",
"info": ""
}
]
}
]
}
Dataweave
%dw 2.0
import * from dw::util::Values
output application/json
var calinga = {
"title": "titel",
"Position and contact": "Lage und Kontakt"
}
---
payload.sections map (item,index)->(item mapObject ((value, key, index) -> {'$(key)' : value} update field("calingaKey") with calinga.'$(key)' ))
"calinga.'$(key)'" doesn't seem to work for some reason, and gives me null, any issue with my code?
Expected Output
[
{
"title": "Identification",
"calingaKey": "titel",
"content": [
{
"name": "Classification",
"text": "Product",
"url": "",
"info": ""
},
{
"name": "Product Number",
"text": "####1234",
"url": "",
"info": ""
}
]
},
{
"title": "Position and Contact",
"calingaKey": "titel",
"content": [
{
"name": "Manufacturer",
"text": "Value of Manufacturer",
"url": "",
"info": ""
},
{
"name": "Hardware Version",
"text": "####1234",
"url": "",
"info": ""
}
]
}
]
%dw 2.0
import * from dw::util::Values
output application/json
var calinga = {
"title": "titel1",
"calingaKey": "titel1",
"Position and contact": "Lage und Kontakt"
}
---
payload.sections map (item,index)->(item mapObject ((value, key, index) -> {'$(key)' : value} update field("calingaKey") with calinga[key]
))

Delete property from nested object using Lodash

Hi I have the following object:
{ "name": "Joe", "email": "joe.smith#test.com", "items": [ { "id": "1", "name": "Name 1" }, { "id": "2", "name": "Name 2" }...] }
I need to remove the name property from all the 'items', I have tried using omit but can't seem to get this working:
_.omit(this.user, ["items.name"]);
Any help would be great!
The _.omit() method doesn't work on multiple items in this way. You can use _.map() with _.omit():
const user = { "name": "Joe", "email": "joe.smith#test.com", "items": [ { "id": "1", "name": "Name 1" }, { "id": "2", "name": "Name 2" }] }
const result = {
...user,
items: _.map(user.items, user => _.omit(user, 'name'))
}
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Merge two json payload with dataweave

I have a Mule flow that calls two REST API's resulting in two json list payloads. I need to obtain a merged json list from these two payloads.
I managed to achieve this with a scatter-gather flow with a custom aggregator strategy. However the code I had to write for this looks rather messy and it's slow.
Is there any way to achieve this using dataweave?`
input Json list 1:
[{
"ID": "1",
"firstName": "JANE""familyName": "DOE",
"Entities": [{
"ID": "515785",
"name": "UNKOWN UNITED",
"callSign": "UU"
}]
},
{
"ID": "2",
"firstName": "JOHN",
"familyName": "DOE",
"Entities": [{
"Entities_ID": "515785",
"name": "UNKOWN UNITED",
"callSign": "UU"
}]
}]
input Json list 2:
[{
"ID": "1",
"firstName": "JANE",
"familyName": "DOE",
"Entities": [{
"Entities_ID": "8916514",
"name": "UNKOWN INCORPORATED",
"callSign": "UI"
}]
},
{
"ID": "4",
"firstName": "JAKE",
"familyName": "DOE",
"Entities": [{
"Entities_ID": "8916514",
"name": "UNKOWN INCORPORATED",
"callSign": "UI"
}]
}]
desired output is a merged list without duplicate IDs:
[{
"ID": "1",
"firstName": "JANE",
"familyName": "DOE",
"Entities": [{
"Entities_ID": "515785",
"name": "UNKOWN UNITED",
"callSign": "UU"
},
{
"Entities_ID": "8916514",
"name": "UNKOWN INCORPORATED",
"callSign": "UI"
}]
},
{
"ID": "2",
"firstName": "JOHN",
"familyName": "DOE",
"Entities": [{
"Entities_ID": "515785",
"name": "UNKOWN UNITED",
"callSign": "UU"
}]
},
{
"ID": "4",
"firstName": "JAKE",
"familyName": "DOE",
"Entities": [{
"Entities_ID": "8916514",
"name": "UNKOWN INCORPORATED",
"callSign": "UI"
}]
}]
This works for me with dataweave where payload is list1 and flowVars.list2 is list2
%dw 1.0
%output application/json
%var mergeddata = flowVars.list2 groupBy $.ID
---
payload map ((data,index) -> {
ID: data.ID,
firstName : data.firstName,
familyName : data.familyName,
Entities : data.Entities ++ (mergeddata[data.ID].Entities default [])
}) ++
(flowVars.list2 filter (not (payload.ID contains $.ID)))
Hope this helps