My Input Request JSON looks like this below:
{
"phoneNumbers": [{
"phoneNumberType": "mobile",
"phoneNumber": "54112724555"
},
{
"phoneNumberType": "mobile",
"phoneNumber": "16298765432"
}
]
}
I want to generate Output Json Like this :
{
"phoneNumbers": [{
"phoneNumberType": "mobile",
"phoneNumber": "54112724555",
"CountryCode": "ARG"
},
{
"phoneNumberType": "mobile",
"phoneNumber": "16298765432",
"CountryCode": "US"
}
]
}
I derive the countryCode from the PhoneNumber using callingCode and CountryCode Mapping given in csv file.
CALLING_CODE,COUNTRY_CODE
1,US
7,RU
54,AR
20,EG
32,BE
33,FR
505,NI
506,CR
1876,JM
1905,CA
1939,PR
262262,RE
262269,YT
.,.
.,.
I have used the fileConnector to read the CSV File and stored it in Vars.CallingCodeMapping.
I have to do lookup phoneNumber with calling code by passing first letter from the phonenumber matching return countryCode then first two letter ....firstsixLetter if nothing matches return NA.
Given this input as payload
[
"54112724555",
"16298765432"
]
And this csv in a var called country_codes
%dw 2.0
output application/json
var codeByCode = vars.country_code groupBy ((item, index) -> item.CALLING_CODE)
/**
* Returns the Country code or Null if not found
*/
fun lookupCountrCode(phoneNumber:String): String | Null =
//map the each sub part to a country code or null
(0 to 6 map ((index) -> codeByCode[phoneNumber[0 to index]])
//Filter non null and take the first this will return null if array is empty
filter ((item, index) -> item != null))[0]
---
payload map ((item, index) -> lookupCountrCode(item))
Outputs
[
[
{
"CALLING_CODE": "54",
"COUNTRY_CODE": "ARG"
}
],
[
{
"CALLING_CODE": "1",
"COUNTRY_CODE": "US"
}
]
]
Related
Hi everybody i hope you are well, i have a doubt how can i do to use the try inside map in dataweave, i explain about my issue, i receive a csv file with multiple rows, that rows are group by order first and the second, i use map to transform the data in json ( to join all the rows with the same order) format using a couple colums that colums coming from the csv file, if any colum has empty or null the map fail and broke all the content file, how can i use the try function in dataweave if any group of orders fail only get the order and put in another part of the json and follow with the next order without broke the loop.
Part of the CSV File - Demo:
number,date,upc,quantity,price
1234556,2022-08-04,4015,1,
1234556,2022-08-04,4019,1,2.00
1234556,2022-08-04,4016,1,3.00
1234557,2022-08-04,4015,1,3.00
Dataweave:
%dw 2.0
output application/json
---
payload groupBy ($.number) pluck $ map ( () -> {
"number": $[0].number,
"date": $[0].date,
"items": $ map {
"upc": $.upc,
"price": $.price as Number {format: "##,###.##"} as String {format: "##,###.00"},
"quantity": $.quantity
}
})
Error Message:
Unable to coerce `` as Number using `##,###.##` as format.
NOTE: if put the data in the position "price "= something the the issue are solve in the first row, but i need use the function try or what do you recomend, i cant validate all the elements in csv because this is a demo the complete file has a many columns... if you would has another coment to better my code i'd apreciated.
Expected Result: (I don't know if this is possible)
[
{
"data": [
{
"number":"1234557",
"date":"2022-08-04",
"items":[
{
"upc":"4015",
"price":"3.00",
"quantity":"1"
}
]
}
]
},
{
"Error":[
{
"number":"1234556",
"message":"Unable to coerce `` as Number using `##,###.##` as format."
}
]
}
]
best regards!!
Hi The closer I got from what you asked for was
%dw 2.0
output application/json
import * from dw::Runtime
fun safeMap<T, R>(items: Array<T>, callback: (item:T) -> R ): Array<R | {message: String}> =
items map ((item) -> try(() -> callback(item)) match {
case is {success: false} -> {message: $.error.message as String}
case is {success: true, result: R} -> $.result
})
---
payload
groupBy ($.number)
pluck $
safeMap ((item) -> {
"number": item[0].number,
"date": item[0].date,
"items": item safeMap {
"upc": $.upc,
"price": $.price as Number {format: "##,###.##"} as String {format: "##,###.00"},
"quantity": $.quantity
}
})
This uses a combination of map and try function.
And it outputs
[
{
"number": "1234556",
"date": "2022-08-04",
"items": [
{
"message": "Unable to coerce `` as Number using `##,###.##` as format."
},
{
"upc": "4019",
"price": "2.00",
"quantity": "1"
},
{
"upc": "4016",
"price": "3.00",
"quantity": "1"
}
]
},
{
"number": "1234557",
"date": "2022-08-04",
"items": [
{
"upc": "4015",
"price": "3.00",
"quantity": "1"
}
]
}
]
If you are looking to resolve the value of price if price is null/empty value in the input csv and get rid of the error(which is happening because it cannot format Null values to Number) , try adding default in case of empty/null values and formatting to String only when value exists, like below:
%dw 2.0
output application/json
---
payload groupBy ($.number) pluck $ map ( () -> {
"number": $[0].number,
"date": $[0].date,
"items": $ map {
"upc": $.upc,
"price": ($.price as String {format: "##,###.00"}) default $.price,
"quantity": $.quantity
}
})
Note:
For price, you don't need to convert to Number at all if you want your output as formatted string ultimately.
How to write Dataweave transformation in Anytime Studio for given input and output of Json array.
Input:
{
"result": [{
"Labels": [{
"value": [{
"fieldName": "firstName",
"value": "John"
},
{
"fieldName": "lastName",
"value": "Doe"
},
{
"fieldName": "fullName",
"value": "John Doe"
}
]
}]
}]
}
Output:
{
"result": [{
"Labels": [{
"value": [{
"firstName": "John",
"lastName": "Doe",
"fullName": "John Doe"
}]
}]
}]
}
https://docs.mulesoft.com/dataweave/2.4/dw-core-functions-reduce Reduce function might be the one should be used
Thank you in advance
You can just use map to map all the arrays to required format. For the value part you can map the values as fieldName: value array and deconstruct them to an object by wrapping the array around parentheses
%dw 2.0
output application/json
---
{
result: payload.result map ((item) -> {
Labels: item.Labels map ((label) -> {
value: [
{
(label.value map ((field) ->
(field.fieldName): field.value
)) //wrap the array, i.e. lavel.value map ... in parentheses so that it will give you individual key pair.
}
]
})
})
}
You can try below if you are aware that the keyNames will not change:
%dw 2.0
output application/json
---
payload update {
case res at .result -> res map (res, resIndex) -> (res update {
case lbl at .Labels -> lbl map (lbl, lblIndex) -> (lbl update {
case val at .value -> [
(val reduce ((item, acc = {}) -> acc ++ {
(item.fieldName): (item.value)
}))
]
}
)
}
)
}
Here's 2 caveats and a solution. Your input and output files, both are not valid JSON.
Input file, in your "result" object, "Labels" need curly braces {} since they are objects. Key-value pairs should look like this {key:value} not like that key:value
Output file, inside your "value" arrays, key-value pairs need to have the curlies {key:value}
So here's a valid JSON version of your input
{
"result": [
{"Labels": [
{
"value": [
{"fieldName": "firstName","value": "John"},
{"fieldName": "lastName","value": "Doe"},
{"fieldName": "fullName","value": "John Doe"}
]
}
]},
{"Labels": [
{
"value": [
{"fieldName": "firstName","value": "John"}
]
}
]}
]}
Here's a solution
%dw 2.0
import keySet from dw::core::Objects
// this is "result"
var layer1key = keySet(payload)[0]
// this is "Labels" and grabs the first Labels, so assumes Labels doesn't change
var layer2 = payload[layer1key]
var layer2key = keySet(layer2[0])[0]
// this is "value"
var layer3 = layer2[layer2key]
var layer3key = keySet(layer3[0][0])[0]
// this is "fieldName" and "value"
var layer4 = layer3 map (x) -> x['value']
var data1 = ((layer1key) : layer4 map (x) -> {
(layer2key): x map (y) -> {
(layer3key): y map (z) -> {
(z['fieldName']):z['value']
}
}
})
output application/json
---
data1
And a valid JSON version of your output
{
"result": [
{
"Labels": [
{
"value": [
{
"firstName": "John"
},
{
"lastName": "Doe"
},
{
"fullName": "John Doe"
}
]
}
]
},
{
"Labels": [
{
"value": [
{
"firstName": "John"
}
]
}
]
}
]
}
I need to compare two fields in a array and replace their values with different data and output in separate objects
Here is my sample input array:
{
"data": [
{
"house": "house1",
"condition": "bad",
"age": "old",
},
{
"house": "house2",
"condition": "good",
"age": "new",
}
]
}
Output should be
{
"data": [
{
"house": "house1",
"condition": "repair"
},
{
"house": "house1",
"age": "over50",
},
{
"house": "house2",
"condition": "No repair",
},
{
"house": "house2",
"age": "recent"
}
]
}
If condition is "bad" I need to replace with "repair" else if condition is "good" I need to replace with "No repair".
Same type of logic. for the age field. If age is "old" I need to replace with "Over50" and if age is "new" I need to replace with "recent". The two fields(age and condition) are going to be in every iteration
As aled suggested, Map would do this along with OrderBy.
%dw 2.0
output application/json
var a=payload.data
---
"data":(a map{
"house": $.house,
"condition":if (($.condition)=="bad") "repair" else "No repair"
} ++ (a map{
"house": $.house,
"age":if (($.age)=="old") "over50" else "recent"
})orderBy $.house)
Output
{
"data": [
{
"house": "house1",
"condition": "repair"
},
{
"house": "house1",
"age": "over50"
},
{
"house": "house2",
"condition": "No repair"
},
{
"house": "house2",
"age": "recent"
}
]
}
Alternative solution with a single map (you map to an array of the 2 objects required and then flatten the result):
%dw 2.0
output application/json
fun mapCondition(cond : String) = if (cond == "bad") "repair" else "No repair"
fun mapAge(age : String) = if (age == "old") "over50" else "recent"
---
{
data : flatten(payload.data
map ((item, index) ->
[
{
house: item.house,
condition: mapCondition(item.condition)
},
{
house: item.house,
age: mapAge(item.age)
}
]))
}
Use map() over data array and use if conditions to transform the field of each element inside the map. Seems pretty direct.
You can also apply map and flatten with a single call to flatMap.
%dw 2.0
output application/json
---
data: payload.data flatMap [
{
house: $.house,
condition: $.condition match {
case 'bad' -> 'Repair'
else -> 'No Repair'
}
},
{
house: $.house,
age: $.age match {
case 'old' -> 'over50'
else -> 'new'
}
}
]
I have this below payload and I want to remove object where all the keys have ALL empty values,
[
{
"Order" : "123",
"Product" : "456"
},
{
"Order" : "",
"Product" : ""
}
]
This is what the output should be like,
[
{
"Order" : "123",
"Product" : "456"
}
]
None of the posted solutions handle things like nested structures or arrays, so I thought I'd throw this recursive solution in the ring. This allows us to traverse the entire structure of the object until we hit the first non-null field.
%dw 2.0
output application/json
import everyEntry from dw::core::Objects
import every from dw::core::Arrays
var allFieldsNull = (obj: Any) ->
obj match {
case is Object -> obj everyEntry (allFieldsNull($))
case is Array -> (sizeOf(obj) == 0) or (obj every allFieldsNull($))
//case is Array -> false
else -> isEmpty(obj)
}
---
payload filter !allFieldsNull($)
If you wanted to consider an empty array as enough to keep the object since that technically isn't null, you would just need to comment out the case is Array line and uncomment the one below it.
Input:
[
{
"Order" : "123",
"Product" : "456"
},
{
"Order" : "",
"Product" : "",
"Address": {
"Field1": ""
},
"Test": [
{
"Order" : "",
"Product" : "",
"Address": {
"Field1": ""
}
}
]
},
{
"Order" : null,
"Product" : null,
"Address": {
"Field1": null
},
"Test": [
{
"Order" : null,
"Product" : null,
"Address": {
"Field1": "A value even in a deeply nested field means I show up"
}
}
]
}
]
output:
[
{
"Order": "123",
"Product": "456"
},
{
"Order": null,
"Product": null,
"Address": {
"Field1": null
},
"Test": [
{
"Order": null,
"Product": null,
"Address": {
"Field1": "A value even in a deeply nested field means I show up"
}
}
]
}
]
Would something like this work for you?
Input
[
{
"Order" : "123",
"Product" : "456"
},
{
"Order" : null,
"Product" : null
}
]
Script
%dw 2.0
output application/json
import * from dw::core::Objects
var valuesOfInputObjects = payload map { ($ takeWhile((value, key) -> value == null))}
---
payload -- valuesOfInputObjects
output
[
{
"Order": "123",
"Product": "456"
}
]
You can filter by a condition, using the everyEntry() function to see that not all values are empty.
%dw 2.0
output application/json
import * from dw::core::Objects
---
payload filter ($ someEntry (value, key) -> !isEmpty(value))
Payload :
[
{
"Contacts": "123456,098765",
"Emails" : ""
},
{
"Contacts": "ABC123",
"Emails" : ""
}
]
How can I get a list of all emails from the below array of objects where the contact Id matches from each row in the payload? (Expected output below)
Variable accConts
{
"queryResponse": [
{
"Email": "test123#test.com",
"SalesforceId": "123456"
},
{
"Email": "test#test.com",
"SalesforceId": "098765"
},
{
"Email": "ABC#test.com",
"SalesforceId": "ABC123"
}
]
}
Expected Output:
[
{
"Contacts": "123456,098765",
"Emails" : "test123#test.com, test#test.com"
},
{
"Contacts": "ABC123",
"Emails" : "ABC#test.com"
}
]
HTH..
%dw 2.0
output application/json
var qResp ={
"queryResponse": [
{
"Email": "test123#test.com",
"SalesforceId": "123456"
},
{
"Email": "test#test.com",
"SalesforceId": "098765"
},
{
"Email": "ABC#test.com",
"SalesforceId": "ABC123"
}
]
}
---
payload filter ($.Contacts != null) map using (iter = $$) {
"Contacts" : $.Contacts,
"Emails": (qResp.queryResponse filter (payload[iter].Contacts contains $.SalesforceId)) reduce ((item,acc = "") -> (acc ++ "," ++ item.Email)[1 to -1]
)
}
I accepted Salim Khan's answer as he guided me in the right direction and the logic to get emails worked. I just needed to rework the map logic,
payload map (row, index) -> {
"Contacts" : row."Contacts",
"Emails" : (qResp.queryResponse filter (row."Contacts" contains $.SalesforceId)) reduce ((item,acc = "") -> (acc ++ "," ++ item.Email)[1 to -1]
),
}
Hopefully this comaprision helps
Wanted to add a slightly more succinct solution to show another approach.
%dw 2.0
output application/json
var qResp =
{
"queryResponse": [
{
"Email": "test123#test.com",
"SalesforceId": "123456"
},
{
"Email": "test#test.com",
"SalesforceId": "098765"
},
{
"Email": "ABC#test.com",
"SalesforceId": "ABC123"
}
]
}
---
payload map (value) ->
{
'Contacts':value.Contacts,
'Emails': qResp.queryResponse[?(value.Contacts contains $.SalesforceId)]..Email joinBy ", "
}