Dataweave2 Update function for few entries not working? - mule

I want to update 3 fields in my Array of paylaod.
TotalSpendamount
price
lineAmount.
My script is as follows;
%dw 2.0
output application/json
---
payload update {
case .IntegrationEntities.integrationEntity -> $ map {
($ update {
case .integrationEntityDetails.contractUtilization.items.item -> $ map {
($ update {
case .price -> if ( $ as Number < 1 ) "0" ++ $ else $
case .lineAmount -> if ( $ as Number < 1 ) "0" ++ $ else $
})
}
case totalSpendAmount at .integrationEntityDetails.contractUtilization -> totalSpendAmount update
{
case totalSpendAmount at .totalSpendAmount -> if ( totalSpendAmount as Number < 1 ) "0" ++ totalSpendAmount else totalSpendAmount
}
})
}
}
If I run above script, only totalspendAmount' is getting update.If I remove the 'totalspendAmount' case block, my 'price and lineamount fields are updating correctly.
What is wrong in my script?
My payload is;
{
"IntegrationEntities": {
"integrationEntity": [
{
"integrationEntityHeader": {
"integrationTrackingNumber": "XXXX",
"referenceCodeForEntity": "132804",
"additionalInfo": "ADDITIONALINFO"
},
"integrationEntityDetails": {
"contractUtilization": {
"externalId": "417145",
"utilizationType": "INVOICE",
"isDelete": "No",
"documentNumber": "132804",
"documentDescription": "",
"documentDate": "2021-03-26",
"totalSpendAmount": ".92",
"documentCurrency": "AUD",
"createdBy": "Oracle Integration",
"status": "FULLY PAID",
"items": {
"item": [
{
"lineItemId": "132804_1",
"contractNumber": "YYYYYYY",
"contractLineId": "",
"lineNumber": "1",
"name": "132804",
"description": "132804",
"quantity": "1",
"price": ".92",
"lineAmount": ".92",
"purchaseOrderNumber": "YYYYYY",
"purchaseOrderDescription": ""
},
{
"lineItemId": "132804_2",
"contractNumber": "YYYYYYY",
"contractLineId": "",
"lineNumber": "1",
"name": "132804",
"description": "132804_2",
"quantity": "1",
"price": ".95",
"lineAmount": ".95",
"purchaseOrderNumber": "YYYYYY",
"purchaseOrderDescription": ""
}
]
}
}
}
}
]
}
}
The output I look for is;
{
"IntegrationEntities": {
"integrationEntity": [
{
"integrationEntityHeader": {
"integrationTrackingNumber": "XXXX",
"referenceCodeForEntity": "132804",
"additionalInfo": "ADDITIONALINFO"
},
"integrationEntityDetails": {
"contractUtilization": {
"externalId": "417145",
"utilizationType": "INVOICE",
"isDelete": "No",
"documentNumber": "132804",
"documentDescription": "",
"documentDate": "2021-03-26",
"totalSpendAmount": "0.92",
"documentCurrency": "AUD",
"createdBy": "Oracle Integration",
"status": "FULLY PAID",
"items": {
"item": [
{
"lineItemId": "132804_1",
"contractNumber": "YYYYYYY",
"contractLineId": "",
"lineNumber": "1",
"name": "132804",
"description": "132804",
"quantity": "1",
"price": "0.92",
"lineAmount": "0.92",
"purchaseOrderNumber": "YYYYYY",
"purchaseOrderDescription": ""
},
{
"lineItemId": "132804_2",
"contractNumber": "YYYYYYY",
"contractLineId": "",
"lineNumber": "1",
"name": "132804",
"description": "132804_2",
"quantity": "1",
"price": "0.95",
"lineAmount": "0.95",
"purchaseOrderNumber": "YYYYYY",
"purchaseOrderDescription": ""
}
]
}
}
}
}
]
}
}

Try with this script:
%dw 2.0
output application/json
---
payload.IntegrationEntities.integrationEntity.integrationEntityDetails.contractUtilization map ((cu, index) -> cu update {
case .totalSpendAmount if ($ as Number < 1) -> "0" ++ $
case .items.item -> $ map {
($ update {
case .price -> if ( $ as Number < 1 ) "0" ++ $ else $
case .lineAmount -> if ( $ as Number < 1 ) "0" ++ $ else $
})
}
})
Updated Scripts:
Approach 1
%dw 2.0
output application/json
---
payload update {
case .IntegrationEntities.integrationEntity -> $ map {
($ update {
case .integrationEntityDetails.contractUtilization-> $ update {
case .totalSpendAmount -> if ($ as Number < 1) "0" ++ $ else $
case .items.item -> $ map ((cuItem,index) -> cuItem update {
case .price -> if ( $ as Number < 1 ) "0" ++ $ else $
case .lineAmount -> if ( $ as Number < 1 ) "0" ++ $ else $
})
}
} )}
}
Approach 2
%dw 2.0
output application/json
---
payload update {
case .IntegrationEntities.integrationEntity[0].integrationEntityDetails.contractUtilization-> $ update {
case .totalSpendAmount -> if ($ as Number < 1) "0" ++ $ else $
case .items.item -> $ map ((cuItem,index) -> cuItem update {
case .price -> if ( $ as Number < 1 ) "0" ++ $ else $
case .lineAmount -> if ( $ as Number < 1 ) "0" ++ $ else $
})
}
}

Related

Derive parent-child hierarchy in JSON from an array using DataWeave

Hopefully this is the last of my questions related to this and this
The earlier questions were related to generating XML payload while this query is around generating JSON o/p in a specific format...
Thanks to #Harshank and #sudhish_s was able to make some progress with XML o/p. However I am not able to figure out how to go about json o/p
Here is the input payload ( have limited it to three rows / json objects but could be in thousands)
[
{
"gp": "S1",
"gp_eye_colour": "blue",
"gp_name" : "John",
"parent": "S1",
"parent_eye_colour" : "blue",
"parent_name" : "Sam",
"child": "C1",
"child_eye_colour" : "black",
"child_name" : "C1-name"
},
{
"gp": "S1",
"gp_eye_colour": "blue",
"gp_name" : "John",
"parent": "P1",
"parent_eye_colour" : "blue",
"parent_name" : "Don",
"child": "C1",
"child_eye_colour" : "brown",
"child_name" : "C1-name"
} ,
{
"gp": "S2",
"gp_eye_colour": "blue",
"gp_name" : "David",
"parent": "P2",
"parent_eye_colour" : "blue",
"parent_name" : "Martha",
"child": "C1",
"child_eye_colour" : "brown",
"child_name" : "C1-name"
}
]
Desired o/p is as below :
{
"S2_blue": {
"code": "S2",
"eyeColour": "blue",
"name": "David",
"hierarchy": [
{
"code": "P2",
"eyeColour": "blue",
"name": "Martha",
"hierarchy": [
{
"code": "C1",
"eyeColour": "brown",
"name": "C1-name",
"hierarchy": []
}
]
}
]
},
"S1_blue": {
"code": "S1",
"eyeColour": "blue",
"name": "John",
"hierarchy": [
{
"code": "P1",
"eyeColour": "blue",
"name": "Don",
"hierarchy": [
{
"code": "C1",
"eyeColour": "brown",
"name": "C1-name",
"hierarchy": []
}
]
},
{
"code": "C1",
"eyeColour": "black",
"name": "C1-name",
"hierarchy": []
}
]
}
}
Similar rules need to apply :
Its a Grandparent >> Parent >> Child hierarchy
If Grandparent and Parent share same characteristics (gp == parent and gp_eye_colour == parent_eye_colour then skip parent and directly include child(ren)
( as an example parent Sam is excluded since John (gp) has the same value for gp and eye_colour
Don is not exluded ( same rule as above )
Using the solutions provided to the earlier asked questions - I came up with the following code:
%dw 2.0
output application/json
var hierarchy = ["gp", "parent", "child"]
fun getDirectGeanologies(records, level) = do {
var hLevel = hierarchy[level]
var xyz = if(level == 0)
(records groupBy ((item, index) -> item.gp ++ "_" ++ item.gp_eye_colour) )
else if(level == 1)
(records groupBy ((item, index) -> item.parent ++ "_" ++ item.parent_eye_colour))
else
(records groupBy ((item, index) -> item.child ++ "_" ++ item.child_eye_colour))
---
xyz mapObject ((children, code) ->
(code): {
code: children[0][hLevel],
eyeColour: children[0][hLevel ++ "_eye_colour"],
name: children[0][hLevel ++ "_name"],
hierarchy:
if (level == sizeOf(hierarchy) - 1) [] // if level = 2 ( child stop recursion)
else do {
var nextLevel = level + 1
var nextGen = if(nextLevel == 1)(children groupBy ((item, index) -> item.parent ++ "_" ++ item.parent_eye_colour)) else (children groupBy ((item, index) -> item.child ++ "_" ++ item.child_eye_colour))
---
nextGen mapObject ((nextGenChildren, nextGenCode) ->
if (nextGenCode == code)
getDirectGeanologies (nextGenChildren, nextLevel + 1 ) // skip parent
else
getDirectGeanologies (nextGenChildren, nextLevel)
)
}
}
)
}
---
getDirectGeanologies(payload,0)
However it is not producing desired o/p :
{
"S1_blue": {
"code": "S1",
"eyeColour": "blue",
"name": "John",
"hierarchy": {
"C1_black": {
"code": "C1",
"eyeColour": "black",
"name": "C1-name",
"hierarchy": [
]
},
"P1_blue": {
"code": "P1",
"eyeColour": "blue",
"name": "Don",
"hierarchy": {
"C1_brown": {
"code": "C1",
"eyeColour": "brown",
"name": "C1-name",
"hierarchy": [
]
}
}
}
}
},
"S2_blue": {
"code": "S2",
"eyeColour": "blue",
"name": "David",
"hierarchy": {
"P2_blue": {
"code": "P2",
"eyeColour": "blue",
"name": "Martha",
"hierarchy": {
"C1_brown": {
"code": "C1",
"eyeColour": "brown",
"name": "C1-name",
"hierarchy": [
]
}
}
}
}
}
}
The issues here are :
hierarchy inside gp should be an array but I am getting a object
Not 100% sure but because of above problem rather than having objects inside an array against hierarchy I am getting an object with key as parent/child and eye colour ( Ex : C1_black , P1_blue etc )
So not really sure how to get this part and I am having a tough time to visualise the recursive behaviour
Thanks in advance and once again really appreciate the help already provided by #Harshank and #sudhish_s
I have answered this in mulesoft help forum. LInk MuleSoft Help Forum link

dataweave - How can i get total of the order Mule 4

I have the following scenario and problem, I recive by CSV File and mapping with DW, groupping by column "PON", i need to get the total of the order multiply this column ( Qty * Price ), I don't have the correct result, I will show you:
CSV Data:
PON,Item,Qty,Price
PON1000,2015,2,38.08
PON1000,2016,1,33.37
PON1001,2015,2,38.08
DW:
%dw 2.0
output application/json
---
payload groupBy ($.PON) pluck $ map ( () -> {
"order": $[0].PON default "",
"total": (sum( $.Price filter ($ != "") ) as Number) as String {format: "##,###.00"},
"products": $ map {
"product": $.Item,
"price": ($.Price as Number) as String {format: "##,###.00"},
"quantity": $.Qty
}
})
Obtained Result:
[
{
"order": "PON1000",
"total": "71.45",
"products": [
{
"product": "2015",
"price": "38.08",
"quantity": "2"
},
{
"product": "2016",
"price": "33.37",
"quantity": "1"
}
]
},
{
"order": "PON1001",
"total": "38.08",
"products": [
{
"product": "2015",
"price": "38.08",
"quantity": "2"
}
]
}
]
I NEED MULTIPLY BY ORDER THE "price" * "quantity" CORRESPONDENT AND FINALLY SUM THAT VALUE AND PUT IN THE COLUMN total by ORDER
Expected Result:
[
{
"order": "PON1000",
"total": "109.53",
"products": [
{
"product": "2015",
"price": "38.08",
"quantity": "2"
},
{
"product": "2016",
"price": "33.37",
"quantity": "1"
}
]
},
{
"order": "PON1001",
"total": "76.16",
"products": [
{
"product": "2015",
"price": "38.08",
"quantity": "2"
}
]
}
]
Any help would be appreciated. Thank you.
Best Regards!!!
I just added two things:
For the total I used Arrays::sumBy which let's you do an operation on each item and the it sums all the results.
I infered from your code you expect the price to be empty, so I created safeNumber() to check that and return 0 in case it's empty (default did not work).
This is the code I've got so far:
%dw 2.0
output application/json
import * from dw::core::Arrays
fun safeNumber(str) = if(isEmpty(str)) 0 else str as Number
---
payload groupBy ($.PON) pluck $ map ( () -> {
"order": $[0].PON default "",
"total": ($ sumBy( (i) -> safeNumber(i.Qty) * safeNumber(i.Price))) as String {format: "##,##0.00"},
"products": $ map {
"product": $.Item,
"price": safeNumber($.Price) as String {format: "##,##0.00"},
"quantity": $.Qty
}
})
Below script will help you.
%dw 2.0
output application/json
import divideBy from dw::core::Objects
---
payload groupBy $.PON mapObject ((value, key, index) ->
({
order: (key),
total: sum(value map ($.Qty * $.Price)),
value : value
})
) divideBy 3
You can use the following DataWeave expression:
%dw 2.0
output application/json
---
payload groupBy $.PON pluck $ map (() -> {
"order": $[0].PON,
"total": sum($ map ($.Qty as Number * $.Price as Number)),
"products": $ map {
"product": $.Item,
"price": $.Price as Number,
"quantity": $.Qty as Number
}
})

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

How to get all values where a certain Key matches in Dataweave 2.0?

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

Mule transform message move out list of objects from array to objects

Mule Transform Message:
%dw 1.0
%function removeEmptyInArray(arr) arr map (
(removeEmptyInArray($) when $ is :array
otherwise (removeEmptyInObject($) when $ is :object
otherwise $ when ($ != null and (sizeOf $) > 0) otherwise null))
) when arr != []
otherwise null
%function removeEmptyInObject(obj) obj mapObject (
'$$': (removeEmptyInArray($) when $ is :array
otherwise (removeEmptyInObject($) when $ is :object
otherwise $ when ($ != null and (sizeOf $) > 0) otherwise null))
)
%output application/json skipNullOn="everywhere" , encoding='UTF-8'
%namespace ns0 http://xxxxx
%namespace ns1 http://xxxxx
%function getKey(key) (capitalize key) replace /\s/ with '' replace /Tns:/ with '' replace /tns:/ with ''
%function convert(obj) obj mapObject {
(getKey($$)) : convert($) when ($ is :object) otherwise $
}
---
{
"Header": {
"H1": {
"ID": sessionVars.ID ,
"UID": sessionVars.UID
}
},
"Body": removeEmptyInObject(convert(payload))
}
Responses:
First Response:
"Details": [{
"A": {
"A1": {
"A11": ""
},
"A2": {
}
"A3": ""
}
},
{
"B": {
"B1": {
"B11": ""
},
"B2": ""
}
}]
Second Response:
"Details": {
"A": {
"A1": {
"A11": ""
},
"A2": ""
}
}
The two response comes for different persons so the response can very based on ID.
But i need that every time the response should come as an object not like Array [] and i also can not hard coded the whole payload as payload can be changed as per the request.
Expected Response for first type of request:
"Details":
"A": {
"A1": {
"A11": ""
},
"A2": {
}
"A3": ""
}
},
{
"B": {
"B1": {
"B11": ""
},
"B2": ""
}
}
If you're just looking to take:
{
"Details": [
{
"A1": {}
},
{
"A2": {}
}
]
}
And turn it into:
{
"Details": {
"A1": {},
"A2": {}
}
}
In other words "reduce" an array to an object: you can do that with reduce:
payload.Details reduce ((detail, obj={}) ->
obj ++ detail
)
Or you can use the shorthand:
payload.Details reduce $$ ++ $
This is explained in detail here.