how properly to add and remove elements from payload? (or replace on condition) - mule

So I have payload that have old type of attributes, and I want to migrate them to be as new ones that all the rest logic is using. So before do validation I want modify it a bit.
Currently I manage to add and remove in separate transforms, but should it be possible to do in one go?
example payload:
{
"country": "Country",
"town": "Town",
"district": "Dist",
"owner": "Owner"
}
and output should be:
{
"country": "Country",
"city": "Town",
"area": "Dist",
"owner": "Owner"
}
so I add transform:
%dw 1.0
%output application/json
---
payload ++ {city: payload.town}
when
payload.town != null
otherwise
payload ++ {area: payload.distrinct}
when
payload.distrinct != null
otherwise
payload
I want to check if payload have no null values in town key and add new key city with town key value, and same check if distrinct is not null then add its value as area key. However its happening only for city (I know it will be added at the bottom, but order is not a problem in my case) however keys may not present (it may no town, or may no distrinct or may no both)
And on next transform:
%dw 1.0
%output application/json
---
payload -- {town: payload.town}
when
payload.town != null
otherwise
payload
I try to check if keys exist then delete old ones, but no luck on such :(
Any help?

That's too complicated. Instead of adding and removing keys you can just use mapObject to transform each key. Then it becomes trivial to parametrize the transformation. Also using default is simpler than when...otherwise when a value is null.
%dw 1.0
%output application/json
%var keyMap={ town: "city", district: "area" }
%function replaceKey(keyName) (keyMap[keyName] default keyName)
---
payload mapObject ( (replaceKey($$)) : $ )

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
}))

Extracting a subset of JSON key-value pairs as an Object from a Parent JSON Object in dataweave 2.0 Mule 4

I have a dataweave challenge which I couldn't figure out without making it complicated.
Input JSON payload
{
"Name" : "Mr.wolf",
"Age" : 26,
"Region" : "USA",
"SubRegion": "Pacific"
}
Output needed
{
"Name" : "Mr.wolf",
"Age" : 26
}
Here is a catch. I am not allowed to use the above shown output format structure in the transform message, or either remove the keys using "-" operation.
So basically, we shouldn't use the below dwl.
%dw 2.0
output application/json
---
(payload - "Region" - "SubRegion")
or
%dw 2.0
output application/json
---
{
"Name" : payload.Name,
"Age" : payload.Age
}
How can we achieve the required output by using Lambdas, Reduce, mapObject, functions or any other operation of choice, other than the restricted methods/usage shown above.
Any solution provided is much appreciated.
is this what you are looking for?
%dw 2.0
output application/json
---
payload filterObject ((value, key,index) -> (index <2 ))
Sounds like filterObject could work for you. Documentation
payload filterObject ((value, key) -> (key ~= "Name" or key ~= "Age"))
Another rendition of the same approach.
%dw 2.0
output application/json
---
payload mapObject {
(($$) : $) if (($$) ~= "Name" or ($$) ~= "Age")
}
The other rendition being:
%dw 2.0
output application/json
---
payload mapObject {
(($$) : $) if (($$$) < 2)
}

Mule Dataweave : Filter in combination with Default function not working

Im using Mule dataweave, here is my request, i want to filter my request to code == "P" if request containing Code = p not present then always default to code == "C" because code = C always present in the incoming request.
Request:
{
"addresses": [
{
"contact": 0,
"code": "P",
"TypeDescription": "POSTAL",
"postcode": "1007",
"State": "TamilNadu",
"Description": "Test",
},
{
"contact": 1,
"code": "C",
"TypeDescription": "PHYSICAL",
"postcode": "Bangalore",
"State": "",
"Description": "NEW",
}
]
}
Dataweave:
%dw 1.0
%output application/json
---
payload.addresses filter $.code == "P"
It is working fine and filtering out the P containing list, but when try filter in combination with default it dont wont.
I have tried as below in dataweave payload.addresses filter $.code == "P1" default "anything here as of now".
Since in the above response i'm filtering P1 which is not present in the request hence im expecting the default stuff in the response. But it is not working.
Note: Using when and otherwise, bringing the list twice. I need only one list as response either Code P containing list or C containing list.
Using MUle 3.8.5 V. Please let me know your thoughts. Thanks in advance.
From what I understand, Dataweave works from right to left, so in this case is evaluating like this:
'"P1" default "anything here as of now"' resolves to "P1"
run 'filter $.code == "P1"' over 'payload.addresses'
Of course that first option will always evaluate to "P1" so the default is essentially ignored. You need to use parentheses around the rest of the expression, then follow it with default. Now it will evaluate the parentheses then the default expression.
eg: (payload.addresses filter $.code == "P1") default "anything here as of now"
This is not a good example though, as filter will return an empty list if none of the options match, not null, so the default won't work. You could try something like in this answer: https://stackoverflow.com/a/44431546/2614624
Create a default value in local variable and use an OR condition while filtering.
Example below.
{
biggerThanTwo: [0, 1, 2, 3, 4, 5] filter (($ > 2) OR ($ ==1))
}
Here is my Solution. As #Clinton mentioned Filter returns Empty array not null, here is the way it worked out
%dw 1.0
%output application/java
%var conditionalRoute = payload.addresses filter $.addressTypeCode == "P"
conditionalRoute when conditionalRoute != [] otherwise "anything here as of now"

Create json array using dataweave

If I have xml like so....
<Root>
<Authority>Water</Authority>
<Sanctions>
<Sanction>
<SanctionCode>11</SanctionCode>
<SanctionDesc>First Sanction</SanctionDesc>
</Sanction>
<Sanction>
<SanctionCode>11</SanctionCode>
<SanctionDesc>Second Sanction</SanctionDesc>
</Sanction>
</Sanctions>
</Root>
Using DataWeave how can I create a json array of Santions using only the SanctionDesc?
I've tried this but it's not right...
%dw 1.0
%output application/json
---
records: payload.Root map {
Authority: $.Authority,
sanctions: $.Sanctions.Sanction map [$.SanctionDesc]
}
I want my output to look like this...
{
"records": [{
"Authority": "Water",
"sanctions": ["First Sanction", "Second Sanction"]
}]
}
Try this
%dw 1.0
%output application/json
---
records: {
Authority: payload.Root.Authority,
sanctions: payload.Root.Sanctions..SanctionDesc
}
Or
%dw 1.0
%output application/json
---
records: {
Authority: payload.Root.Authority,
sanctions: payload.Root.Sanctions.*Sanction map $.SanctionDesc
}
Hope this helps.
Understading the map operator is the key when picking and choosing elements from input payload. Map operator goes through all the array elements on the left hand side and we can pick the values from on right hand side, Giving example from Mulesoft portal
%dw 1.0
%output application/json
users: ["john", "peter", "matt"] map ((firstName, position) -> position ++ ":" ++ upper firstName)
Output:
{
"users": [
"0:JOHN",
"1:PETER",
"2:MATT"
]
}
See link below:
https://docs.mulesoft.com/mule-user-guide/v/3.8/dataweave-operators#map

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"
}]