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

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

Related

Transformation of Json array in Dataweave

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

how to remove objects that have all keys with null values in dataweave?

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

Transformation of JSON data in mule 4

I have a requirement wherein I have to convert JSON data from one format to other.
I have to fetch corresponding values of JSON array and make them a key value pair.
Below are the required details:
Input:
"Headers": {
"Header": [
{
"Key": "SellerOrganization",
"Value": "XYZ"
},
{
"Key": "SellerType",
"Value": "B2C"
},
{
"Key": "Region",
"Value": "SOUTH"
},
{
"Key": "OrderType",
"Value": "RETURN"
},
{
"Key": "InvoiceType",
"Value": ""
},
{
"Key": "EventType",
"Value": "Created"
},
{
"Key": "EntryType",
"Value": "Call Center"
}
]
}
Expected Output:
{
SellerOrganization:XYZ,
SellerType: B2C,
Region:SOUTH,
OrderType:RETURN,
InvoiceType:"",
EventType:Created,
EntryType:Call Center
}
You can use the dynamic object that it will basically do what you want.
%dw 2.0
output application/json
---
{
(payload.Headers.Header map ((item, index) -> {
(item.Key): item.Value
})
)
}
You can take advantage of reduce function here which will let you convert your array to an key, value pair object
%dw 2.0
output application/json
---
payload.Header reduce ((item, acc = {}) -> acc ++ {
(item.Key): item.Value
})

How can I transform an array of objects to an array of strings and not lose the key in Dataweave?

Hi I need to transform the following JSON object:
{
"products": [
{
"itemno": "123131",
"description" : "Big Widget",
"attributes": [
{
"color": [
{
"value": "Red",
"codeValue": "RED_NO2"
},
{
"value": "Blue Licorice",
"codeValue": "BLUE-355"
}
]
},
{
"chemicals": [
{
"value": "Red Phosphorous",
"codeValue": "RED_PHOS"
},
{
"value": "Chlorine Bleach",
"codeValue": "CHLRN_BLCH"
}
]
}
]
}
]
}
I am trying to transform this with each attribute having an array of values where their value is the codeValue and it's an array of those string values.
This is the desired output:
{
"products": [
{
"itemno": "123131",
"description: : "Big Widget",
"attributes": [
{
"color": ["RED_NO2", "BLUE-355"]
},
{
"chemicals": ["RED_PHOS", "CHLRN_BLCH"]
}
]
}
]
}
This is the Dataweave. I cannot determine how to get the attribute names (i.e. color, chemicals as keys with the desired data.
There is not a lot of good examples on transforming data with Dataweave and I have spent a lot of time trying to figure this out.
This is one of the dataweaves that got there somewhat, but isn't the solution:
%dw 1.0
%output application/json
---
payload.products map
{
"ItemNo" : $.sku,
"Desc" : $.description,
"Test" : "Value",
"Attributes" : $.attributes map
{
'$$' : $ pluck $.value
}
}
Your help is greatly appreciated.
You can do something like this:
%dw 1.0
%output application/json
%function attributeCodeValues(attributes)
attributes map ((attr) ->
attr mapObject ((values, descriptor) ->
{
(descriptor): values map $.codeValue
}
)
)
---
payload.products map {
"ItemNo" : $.sku,
"Desc" : $.description,
"Test" : "Value",
"Attributes" : attributeCodeValues($.attributes)
}

Modify Existing Json key : Mule

My Input
{
"Root": {
"order": [
{
"locale": "en-US",
"orderItems": [
{
"product": {
"partNumber": "23853864"
},
"itemSpecifics": {
"options": {
"color": "Olive",
"size": "S"
},
"actualPrice": "7",
"customItemData": {
"TEMP_8401": "8.95",
"TEMP_150207": "3.00"
}
}
}
]
}
... Large amount of JSON Data ...
]
}
}
Expected output
{
"Root": {
"order": [
{
"locale": "en-US",
"orderItems": [
{
"product": {
"partNumber": "23853864"
},
"itemSpecifics": {
"options": {
"color": "Olive",
"size": "S"
},
"actualPrice": "7",
"customItemData": {
"8401": "8.95",
"150207": "3.00"
}
}
}
]
}
... Large amount of JSON Data ...
]
}
}
I want to remove "TEMP_" in the "customItemData" object keys, but I don't want to manually remap the entire JSON object again, assigning properties one by one. Is there any alternative? Any shorter logic in DataWeave? I'm using Mule 3.9.0.
This uses recursion and pattern matching to walk through the data structure and modify the keys. If the key doesn't contain the string "TEMP" it leaves it as is, if it does, it modifies it according to your requirements.
%dw 1.0
%output application/json
%function applyToKeys(e, fn)
e match {
:array -> $ map ((v) -> applyToKeys(v, fn)),
:object -> $ mapObject ((v, k) -> {(fn(k)): applyToKeys(v, fn)}),
default -> $
}
---
applyToKeys(payload,
((key) -> ((key as :string) splitBy "_" )[1]
when ((key as :string) contains "TEMP")
otherwise key))
Please keep in mind the tradeoffs when using a solution like this. The code is certainly less verbose, but it requires a solid understanding of advanced concepts like recursion, pattern matching, lambdas, and higher order functions.