Mulesoft 4 Dataweave for loop and key value pair inside EXCEL TO JSON transformation - mule

I have a data weave transformation converting an excel file to JSON, I had to change the value of an element (column of the file) as per the key-value pair values stored in a variable.
Please let me know how to achieve this.
Below is my data weave which converts 600 rows in the file to a JSON. However, I need to change the value for Brand as per the key-value pair mapping I stored in a variable.
%dw 2.0
output application/json
---
payload map(payload01,index01)->{
city: payload01.City,
province: payload01.Province,
phone: payload01.Phone,
fax: payload01.FAX,
email: payload01.EMAIL,
Brand: payload01.'Fuel Brand'
}

I understand that you want to use the value in attribute 'Fuel Brand' of the input payload to be used as the index in a variable:
%dw 2.0
output application/json
---
payload."Sheet Name" map(payload01,index01)-> {
city: payload01.City,
...
Brand: vars.brandsMapping[payload01.'Fuel Brand']
}
For example if the input is (note: I removed other attributes to simplify the example):
[{City=City A, Fuel Brand=brand1}, {City=City B, Fuel Brand=brand3}]
And the variable vars.brandsMapping contains:
{brand1=The brand1, brand2=The brand2, brand3=The brand3}
The output will be:
[
{
"city": "City A",
"Brand": "The brand1"
},
{
"city": "City B",
"Brand": "The brand3"
}
]
UPDATE: Since you clarified that you want to a dynamic mapping, the method that can be used for that is mentioned at the documentation page: https://docs.mulesoft.com/mule-runtime/4.1/dataweave-cookbook-map-based-on-an-external-definition

Related

Need to change csv header from camel case to snake case in dataweave

I am working on a pipeline to dynamically dump all columns from the salesforce object to the S3 bucket.
I get all columns for a salesforce object using describe object API. I store all columns into a variable and then create a big SOQL query out of it and submit a bulk query job v2.
Now, this is the main problem. The Column name I am getting from the salesforce connector is in camelCase
[{
"Id": 123,
"FirstName": "Manual",
"MasterRecordId__c" :"abc"
},
{
"Id": 456,
"FirstName": "John",
"MasterRecordId__c" :"def"
}]
But I want column names to be in snake case
[{
"Id": 123,
"first_name": "Manual",
"master_record_id__c":"abc"
},
{
"Id": 456,
"first_name": "john",
"master_record_id__c":"def"
}]
I understand mulesoft has an underscore function to do the same thing, but I am not able to apply any function at "key" level.
Any lead would be really helpful. Please let me know for any questions.
You just have to use mapObject along with the underscore function
%dw 2.0
import underscore from dw::core::Strings
output application/json
---
payload map ((item) ->
item mapObject ((value, key) -> {
(underscore(key)): value
})
)
In case you want Id field to remain as it is, give a try like below:
%dw 2.0
import * from dw::core::Strings
output application/json
---
payload map ($ mapObject ((value, key, index) -> if (capitalize(key as String) == key as String)
{
(key): value
}
else
{
(underscore(key)): value
}))

Validate the json Array with Either one field required in Mule 4

Request Json Looks like the below :-
{
"eNumber": 8506493,
"details": [
{
"id":12345,
"name": xyz123
}
]
}
As part of requirement, I need to check the "details" array that either "id" or "name" field must present. if "id" field is present, "name" is non-mandatory. if "name" field is present, "id" is non-mandatory. Throws error if not met.
I tried few options using filter the details array and check the size of the filtered array in the validation component. It does not seems to be working well. if anyone has got better solutions.please share it here.
This example code will return true or false if it passes your condition
%dw 2.0
import * from dw::core::Arrays
output application/json
---
payload.details every ((item) -> item.id? or item.name?)
The function I'm using is every that checks that all elements in an array passes the given criteria.
Later you can use a choice and a use the raise error or you can use the fail dw function with an if else.
You can restrict it at RAML level.
Sample RAML -
#%RAML 1.0
title: api
types:
test1:
type: object
properties:
id:
type: string
example: 123a
test2:
type: object
properties:
name:
type: string
example: xyz124
test3:
type: object
properties:
enumber:
type: string
example: 8506493a
details :
type: [test1 | test2]
/test:
post:
body:
application/json:
type: test3

Filter Payload with Dataweave for a Set Variable component

For the Mulesoft 4.2 Set Variable component, I want to assign a simple String value pulled from a single specific record from an incoming JSON payload.
In my case, taking just the value from the 'country' field from below example:
[
{
"salesID": "4404Bob Builder210032011-02-18T15:52:21+0.00",
"id": "4404",
"firstName": "Bob",
"lastName": "Builder",
"address": "181 Construction Road, Adelaide, NSW",
"postal": "21003",
"country": "New Zealand",
"creationDate": "2011-02-18T15:52:21+0.00",
"accountType": "personal",
"miles": 17469
}
]
A non-dynamic way to do this is like:
payload[0].country
I believe the best way to do this is with the filter function. The below option gives me the entire object, but I just want the country field.
payload filter ($.id == "4404")
Map function seems to be overkill for this since I only want the value, itself. I must be missing the syntax to get at the country field.
I did some more investigating, and this solution got me close enough to what I wanted:
https://stackoverflow.com/a/43488566/11995149
For my code example using filter, I had to surround the whole expression in parenthesis, and then I can access the field with a dot reference,
but below code gives String value as a single record within an array:
(payload filter ($.id == "4404")).country
[
"New Zealand"
]
In my case, I know that just one result will be returned from the filtered payload, so I could get just the String value with:
(payload filter ($.id == "4404"))[0].country
enter image description here
Can you try any of below options:
1) (payload groupBy ((item, index) -> item.id))["4404"][0].country
OR
2) (payload map ((item, index) -> if(item.id == "4404") item.country else ""))[0]
Thanks,
Ashish

Merge two JSON outputs into one with Dataweave

I currently have two JSON files with data.
The first has a list of actions by a user. However, the userID is a UID string instead of their user name.
The second is a JSON list of UID strings with their corresponding user names. I stored this JSON in a Flow Variable named UserPayload
I'd like to merge the user name into the first list so that my output has actual users names instead of the UID.
Here is what I had so far...but the userId part doesn't work since my flowVar is an list.
%dw 1.0
%output application/csv
---
payload map ((payload01, indexOfPayload01) -> {
user: payload.01.userId,
actions: payload01.action,
FileName: payload01.payload.properties.name default "N/A",
userId: flowVars.UserPayload.objectName
})
Any help would be appreciated. Thanks!
you can access the right object from the UserPayload flowVar by either filtering the content of UserPayload based on userId or creating a associative array from UserPayload.
filtering UserPayload
%dw 1.0
%output application/json
---
payload map (action, index) -> {
user: action.user,
action: action.action,
FileName: action.FileName,
userId: (flowVars.UserPayload filter $.objectId == action.user)[0].objectName
}
associative array
%dw 1.0
%output application/json
%var users = flowVars.UserPayload groupBy $.objectId
---
payload map (action, index) -> {
user: action.user,
action: action.action,
FileName: action.FileName,
userId: users[action.user][0].objectName
}
for my examples i used following sample data derived from your question.
flowVars.UserPayload
[{
"objectId": "0000-0000-0001",
"objectName": "first user"
}, {
"objectId": "0000-0000-0002",
"objectName": "second user"
}]
payload
[{
"user": "0000-0000-0001",
"action": "some crazy action",
"FileName": "some-crazy-action.mov"
}]

How to get unnamed object instead of an array in case of only one result in Dataweave

We have a transformation with Dataweave which processes a list of objects. We get a json response like that:
{"hotels": [{
"name": "Hotel Oslo",
"propertyCode": "12345",
"currency": "NOK"
},
{
"name": "Hotel Stockholm",
"propertyCode": "12346",
"currency": "SEK"
}]}
However, in the case of only 1 response, we want to have the following response:
{"name": "Hotel Stockholm",
"propertyCode": "12346",
"currency": "SEK"}
We are generating the response like this:
{
hotels: payload.rows map ((row , indexOfRow) -> {
name: row.content.companyName.content,
propertyCode: row.content.propertyCode.content,
currency: row.content.currencyCode.content
})}
What should we put as a condition so that we do not get an array in case of 1 result?
Try this:
%dw 1.0
%output application/json
%function makeHotel(row) {
name: row.name,
propertyCode: row.propertyCode,
currency: row.currency
}
---
{
hotels: payload.rows map ((row , indexOfRow) -> makeHotel(row))
} when ((sizeOf payload.rows) != 1)
otherwise makeHotel(payload.rows[0])
It will give you an empty array on empty input, the simple object for one input and the structure with array when you have more than one input row.
(For test purposes, with a slightly differnt input structure, but the general solution should be clear.)