Dynamically reference payload field names in Dataweave - mule

I am using Anypoint Studio 7.3 and Mule 4.1.
I am looking to dynamically pass the field name from a JSON payload when transforming a message so on the 1st call I want to use the values in the "cat_name" field and when I call it a 2nd time I want to use the values in the "dog_name" field as the output message structure will be the same. So for "cat_name" I would want $.(vars.codetest) to be resolved as payload.cat_name and for "dog_name" I would want $.(vars.codetest) to be resolved as payload.dog_name
Is there a way of doing this?
%dw 2.0
output application/json
---
(payload distinctBy $.#[vars.codetest]) map ((payload01, indexOfPayload) ->{
name: $.(vars.codetest)
})
Thanks for any help

Something like this should work:
%dw 2.0
output application/json
---
payload
distinctBy $[vars.codetest]
map ((element) -> { name: element[vars.codetest] })
You might need parens around codeTest (i.e. (vars.codetest)) so that it gets evaluated before the lookup.

Related

mule3 to mule 4 expression to dataweave 2.0

I'm new to migrating the mule 3 apps to mule 4 I have done almost conversion but one expression stopped my flow and not able to achieve the logic for it if anyone has an idea regarding the expression to transform please help me
Expression:
if(flowVars.maindata.keySet().contains(payload.idCaseNumber))
{
flowVars.temporary=[];
flowVars.maindata.get(payload.idCaseNumber).add(map);
}
else
{
flowVars.temporary.add(previousdata);
vars.maindata.put(payload.idCaseNumber,temporary);
}
I have tried up to my knowledge on the above code but still I'm getting problem
flowVars.maindata.get(payload.idCaseNumber).add(map);
In Mule 3 the expression language is MEL. In Mule 4 it is DataWeave 2.0. You can't just translate directly. MEL is an imperative scripting language, similar to a subset of Java and it is easy to call Java methods. DataWeave 2.0 is a functional language. Furthermore Mule 4 operations (example: a , , etc) can only return one value, which can be assigned to the payload or to one variable.
For your snippet I'll assume that maindata is a map. You can use two set-variable to assign each variable:
<set-variable variableName="temporary" value="#[ if( namesOf(vars.maindata) contains payload.idCaseNumber ) [] else vars.temporary ++ **previousdata** ]" />
I don't know exactly what do you use for previousdata.
To update the variable maindata it is probably a good match for the update operator, in a separate or Transform operation, with the same condition than for vars.temporary.
Update:
I'll assume vars.maindata is a map, which DataWeave will consider an object, and each element is a list. As an example of doing an 'upsert' operation with a dynamic selector:
%dw 2.0
output application/java
var temporary=[5]
var maindata={ a:[1,2,3,4] }
var myKey="a"
---
maindata update {
case data at ."$(myKey)"! -> if (data != null) data ++ temporary else temporary
}
You could replace in above script the DataWeave var temporary with the expression from my example above, and the other DataWeave variables with the Mule variables (vars.name) or payload. If you change in above example myKey to have value "b" you will see that key being added.

Mulesoft Dataweave convert CSV to map dynamically

I've created a flow that accepts a CSV via a form-data API POST and then processes each row in a batch job. Ideally, I do not want to hand-map each column before passing it to the batch executor, but I could not figure out how to just "pass through" the key/value pairs dynamically. I want to ensure that the CSV can have new columns and we'll pass them through without knowing about them beforehand... This is what I have:
%dw 1.0
%output application/java
---
payload map {
title: $.title,
description: $.description,
template_id: $.template_id,
pricing_flat_price: $.pricing_flat_price,
scheduled_start_date: $.scheduled_start_date,
resource_id: $.resource_id,
industry_id: $.industry_id,
owner_email: $.owner_email,
location_offsite: $.location_offsite
}
And this is what I'm going for (in non-sensical psuedocode):
%dw 1.0
%output application/java
---
payload map {
*:*
}
I have to imagine this is easily done, but I couldn't figure it out.
Thank you,
Steve
You can simply use transformation like below -
%dw 1.0
%output application/java
---
(payload)
hand-map each column before passing it to the batch executor
You shouldn't need to do this. Pass the whole csv to the batch-input phase and allow it to split each line into a Linked Hashmap.

Converting CSV to array using DataWeave

I'm using Mule Requester to load a CSV file. After the file is loaded, the payload is a byte array, which I store in a flow variable, mycsv. I keep getting an exception.
org.mule.api.MessagingException: Exception while executing:
NetIds: flowVars.mycsv map $."My Column Name"
^
Cannot coerce a :binary to a :array (com.mulesoft.weave.mule.exception.WeaveExecutionException). Message payload is of type: byte[]
Here's my DataWeave code:
%dw 1.0
%output application/java
---
{
Values: flowVars.mycsv map $."My Column Name"
}
The previous flow element is a choice, so I set the metadata on that to output to a FlowVar with the right name and referenced a sample CSV file, so DataWeave things the variable type is List<Csv>.
How can I read the CSV? Thanks!
It's because it doesnt know the mimeType of the flowVar because it's not set. Try this before the dataweave transformer:
<set-variable value="#[flowVars.mycsv]" variableName="mycsv" mimeType="application/csv" doc:name="Variable" />
or set the mimeType when you first read the csv.
This is the first time I found a requirement to put two different formats into one csv file. In order to get the expected result, I prefer to use this trick:
Create both expressions and combine them into one simple array, using flatten
Add an empty object as line separator

How to refer payload which is a ResultSet Iterator in mule dataweave?

Sql query returns a streamed output as Resultset iterator object from the Database component.
i want to convert this to xml in dataweave. But don't know how to refer the incoming object,
If it's a map i can access it simply by using .operator like payload.student
Tried using payload.next() but it gives an error. Also tried the following,
%var input1 payload as :iterator but still wont' work
Here the steps:
Drag and drop the Transform Message (Dataweave) component after your configured DB Connector. You will see that the input payload for dataweave script is filled with the db result List<Map>.
Then you can access the fields, using the map function in dw.
dw script
%dw 1.0
%output application/xml
---
{
"Results":{
(payload map {
"key1":$."db_field1",
"key2":$."db_field2"
})
}
}
Can you post your code (XML) and a screenshot of dataweave or debugger?
My first guess would be to use a standard transfomer to transform that object to a list or map before the dataweave transformer.

Transform list of objects into csv using dataweave

I am trying to transform a list of objects to csv using the following code in dataweave:
%dw 1.0
%type company = :object {class: "java.util.ArrayList"}
%input payload application/java
%output application/csv
---
{
name: payload.name,
address: payload.address
} as :company
The below is the output that I get when I execute the above data weave code.
name,name
testName,testName2
testAddress,testAddress2
whilst I am expecting the following: (Sample data)
name,address
testName,testAddress
testName2,testAddress2
Help me understand to what am I missing in the data weave component
In general terms, when using DataWeave you describe your output using a canonical representation which is more or less a super-set of other data formats.
To generate a CSV output you need to generate an array of objects.
Each of these objects represent a CSV row.
Objects in DataWeave are sets of key-value pairs
The mapping should be something like:
%dw 1.0
%output application/csv
---
payload map {
name: $.name,
address: $.address
}
The map operation here generates an object with a name and address for each entry in the list. $ represents the implicit variable under iteration (each list entry).
Note: The %input payload application/java directive is not necessary since the content-type for your input (JSON, XML, CSV, etc) is taken from the mule message when it is set, and it defaults to java if it's not present.
The following works for me:
INPUT:
%dw 1.0
%output application/java
---
[{
name: "nameInput",
address: "addressInput"
}]
MAPPING:
%dw 1.0 %output application/csv
---
payload
OUTPUT:
name,address
nameInput,addressInput
A splitter with xpath as evaluator should do the trick...like:
<splitter evaluator="xpath" expression="/document/article"/>
For me, similar as #Tilo descirbed in his post, but I had to put extra "flatten" because I had Array of Arrays as my input.
MAPPING:
%dw 1.0
%output application/csv
---
flatten payload