Remove object from array based on remove array in Mule 4 - mule

I want to remove all the objects from the users array coming in remove array. Please correct my DataWeave code mentioned below. Expected output is also mentioned.
%dw 2.0
output application/json
var remove =[
{
"startDate": "2022-04-13",
"objectName": "Account"
}
]
var users = [{
"startDate": 20220412,
"objectName": "Account"
},
{
"startDate": 20220412,
"objectName": "Blanket Agreemt"
}
]
---
users filter ((item, index) -> item.objectName != value.objectName) map (value, key) -> {
"objectName": value.objectName
}
Expected output:
[{
"startDate": 20220412,
"objectName": "Blanket Agreemt"
}]

The filter is invalid and the issue unclear. I'll do an educated guess that the objective is to return all elements from the list which their objectName is also present in one of the objects in remove. The map() at the end doesn't seems to be needed.
To resolve we can collect all objectNames into a list with the multi-value selector (remove.*objectName) and use contains() function to check if the current element of users exists in the remove array. Finally the not() is needed to complete the condition for the filter.
%dw 2.0
output application/json
var remove =[
{
"startDate": "2022-04-13",
"objectName": "Account"
}
]
var users = [
{
"startDate": 20220412,
"objectName": "Account"
},
{
"startDate": 20220412,
"objectName": "Blanket Agreemt"
}
]
---
users
filter ((item, index) -> not (remove.*objectName contains ( item.objectName)))

Related

How to use try function with map in dataweave 2.0

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.

Compare multiple fields in a single array and have conditions on their values

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

Navigate to path returned from diff function in dataweave on original payload

I am using dataweave diff function to compare two json objects. Diff is functioning correctly and returning the items that have changed, but it isn't returning anything but the differences. It is returning the path of the item that has changed, but I am not finding a good way to navigate to a string based path. I am only showing one group in the example but there could be many groups by different unique names.
{
"email": "someone#somewhere.com",
"frequency": 1,
"group1": [],
"group2": [],
etc...
)
So here is an example of what I am trying to describe:
Payload 1
{
"email": "someone#somewhere.com",
"frequency": 1,
"group1": [
{
"name": "item1",
"enabled": true
},
{
"name": "item2",
"enabled": true
},
{
"name": "item3",
"enabled": true
}
]
}
Payload 2:
{
"email": "someone#somewhere.com",
"frequency": 1,
"group1": [
{
"name": "item1",
"enabled": true
},
{
"name": "item2",
"enabled": true
},
{
"name": "item3",
"enabled": false
}
]
}
In this case diff between payload 1 and payload 2 would return
{
"matches": false,
"diffs": [
{
"expected": "true",
"actual": "false",
"path": "(root).group1[2].enabled"
}
]
}
I need to reach back into the original payload and navigate to (root).order[2] to get the name key/value pair. What is the best way to do this?
So at the end of the day I need the payload to be:
[
{
name: "item3",
enabled: false,
level: 1
}
]
I appreciate any assistance you can offer. I am also doing a map of the payload level so I know which piece of data to update when I traverse the results. So in this case the level would be 1 based on the fact that is an array off the main object.
This is my current dataweave I just need the first element to be dynamic based on the path that the diff returns
%dw 2.0
output application/json
---
payload.diffs map (item, index) -> {
name: initialPayload.group1[2].name, <-needs to be dynamic based on path
value: (item.actual) replace "\"" with "",
level: sizeOf(item.path splitBy ".")-1
}
I was able to resolve the issue with this weave.
%dw 2.0
fun GetValue(group: String, level: Number, itemkey: String) =
GetKeyValue((((group) splitBy /\./ reduce (e, acc = vars.initialPayload) -> acc[e])[level]), itemkey)
fun GetKeyValue(obj: Object, itemKey: String) =
(entriesOf(obj) filter (item) -> item.key as String == itemKey).value[0]
output application/json skipNullOn="everywhere"
---
{
changes: payload.diffs map (item, index) -> {
name:
if (sizeOf(item.path splitBy ".") - 1 == 1)
((item.path splitBy ".")[1])
else
GetValue((((item.path splitBy ".")[1]) splitBy "[")[0], (((item.path splitBy ".")[1]) splitBy "[")[1] replace "]" with "", "name"),
value: item.actual replace "\"" with "",
level: (sizeOf(item.path splitBy ".") - 1),
}
}

Lookup Country Code from the phone Numbers using Dataweave Mule

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

csv to json conversion where some tags may not come in random

I have a csv input like below: Notice that the tag Edible is not coming for the second set of values. Also notice that the data for one object is coming in columns as well as three rows:
Key|Value|ConcatenatedString
Name|Fruit|"apple,orange,pineapple"
Status|Good|"apple,orange,pineapple"
Edible|Yes|"apple,orange,pineapple"
Name|Furniture|"chair,table,bed"
Status|Good|"chair,table,bed"
I need it in the below json format:
{
Name:"Fruit",
Status:"Good",
Edible:"Yes"
ConcatenatedString:"apple,orange,pineapple"
},
{
Name:"Furniture",
Status:"Good",
Edible:null
ConcatenatedString:"chair,table,bed"
}
I was using the below code when all the tags were coming for all objects. But now that some tags may not come at all I am not sure how to handle this as I was using a position based approach:
%dw 2.0
input payload application/csv separator='|'
output application/json
---
payload map
{
Name:payload[(($$)*4)+0].Value,
Status:payload[(($$)*4)+1].Value,
Edible:payload[(($$)*4)+2].Value,
ConcatenatedString:payload[(($$)*4)+0]."ConcatenatedString"
}
filter ($.Name!= null)
Thanks in advance,
Anoop
here is my answer.
%dw 2.0
input payload application/csv separator="|"
output application/json
---
payload
groupBy ((item, index) -> item.ConcatenatedString)
pluck ((value, key, index) -> {
Name: (value filter ((item, index) -> item.Key == "Name")).Value[0],
Status: (value filter ((item, index) -> item.Key == "Status")).Value[0],
Edible: (value filter ((item, index) -> item.Key == "Edible")).Value[0],
ConcatenatedString: key
})
Basically first you need to group by the criteria you want to group by. In your case ConcatenatedString. This returns
{
"chair,table,bed": [
{
"Key": "Name",
"Value": "Furniture",
"ConcatenatedString": "chair,table,bed"
},
{
"Key": "Status",
"Value": "Good",
"ConcatenatedString": "chair,table,bed"
}
],
"apple,orange,pineapple": [
{
"Key": "Name",
"Value": "Fruit",
"ConcatenatedString": "apple,orange,pineapple"
},
{
"Key": "Status",
"Value": "Good",
"ConcatenatedString": "apple,orange,pineapple"
},
{
"Key": "Edible",
"Value": "Yes",
"ConcatenatedString": "apple,orange,pineapple"
}
]
}
And then you iterate with pluck by every key value pair and filter the elements you want to map.