Using DataWeave to combine CSV payloads - csv

I have a Mule application that needs to produce some CSV output which looks like the following:
[CSV Payload 1]
Data|Data|Data
[CSV Payload 2]
Data|Data|Data|Data|Data|Data|Data|Data|Data
[CSV Payload 3]
Data|Data|Data|Data
[CSV Payload 4]
Data|Data|Data|Data|Data|Data
As you can see, I have a combination of 4 CSV payloads, each with different structures. The first two of these payloads are single line and hard coded. The third is derived from an input file and the fourth is an extract from a database.
My question is: is DataWeave suitable for achieving this or should an alternative method (such as scatter gather) be explored? I've tried to implement this in DataWeave with no luck as I'm struggling to get past the limitation of having to define an output structure.
Please note: the order of the final output needs to be Payload 1 then 2 then 3 then 4. This order cannot be mixed up.

It is not necessary to define an output structure in DataWeave as long as the structure of the data being mapped is compatible with the MIME type defined in the output directive.
You can use a Message Enricher to obtain Payload 4 as an application/java object, and assign it to a flow variable, called for example additionalData.
Then you can used a DataWeave transformation like this, assuming the input payload is derived from the input file (i.e. Payload 3):
%dw 1.0
%output text/csv separator="|", header=false
---
{p1-fld1: "Data", p1-fld2: "Data", p1-fld3: "Data"} +
(
{p2-fld1: "Data", p2-fld2: "Data", p2-fld3: "Data",
p2-fld4: "Data", p2-fld5: "Data", p2-fld6: "Data",
p2-fld7: "Data", p2-fld8: "Data", p2-fld9: "Data"
} +
(payload + flowVars.additionalData )
)
This should produce the target format you need (Payload 1 and Payload 2 are hardcoded objects in the transformation).

Related

Extract nested JSON content from JSON with use of JSON Extractor in jMeter

I have JSON content inside another JSON that I need to extract as it is, without parsing its contents:
{
"id": 555,
"name": "aaa",
"JSON": "{\r\n \"fake1\": {},\r\n \"fake2\": \"bbbb\",\r\n \"fake3\": \"eee\" \r\n}",
"after1": 1,
"after2": "test"
}
When I use JSON Extractor with JSON Path expression:
$.JSON
It returns:
"{
"fake1": {},
"fake2": "bbbb",
"fake3": "eee"
}"
when I need to get the raw string:
"{\r\n \"fake1\": {},\r\n \"fake2\": \"bbbb\",\r\n \"fake3\": \"eee\" \r\n}"
I think you need to switch to JSR223 PostProcessor instead of the JSON Extractor and use the following code:
def json = new groovy.json.JsonSlurper().parse(prev.getResponseData()).JSON
vars.put('rawString', org.apache.commons.text.StringEscapeUtils.escapeJson(json))
You will be able to refer the extracted value as ${rawString} where required.
More information:
Apache Groovy - Parsing and producing JSON
Apache Groovy: What Is Groovy Used For?
console.log(JSON.stringify(data.JSON))
Here data is your given JSON data.
At first, you have to extract your JSON/data. Then you have to stringify the JSON data using JSON.stringify().
The confusing fact you have done here is that you named your key in the JSON object as "JSON".
In js when you extract a JSON object if there is another nested JSON object you will always get JSON data by just data.key_name
where data is JSON data
key is for Nested JSON key

I need to flatten a JSON web response with nested arrays [[ ]] into a DataFrame

I'm trying to convert an http JSON response into a DataFrame, then out to CSV file.
I'm struggling with the JSON into DF.
http line:
http://api.kraken.com/0/public/OHLC?pair=XXBTZEUR&interval=1440
JSON response (part of - 720 records in arrays):
[formatted using a JSON site does not post here apparently]
{
"error": [],
"result": {
"XXBTZEUR": [
[1486252800, "959.7", "959.7", "935.0", "943.6", "945.6", "4423.72544809", 5961],
[1486339200, "943.8", "959.7", "940.0", "952.9", "953.5", "4464.48492401", 7678],
[1486425600, "953.6", "990.0", "952.7", "988.5", "977.3", "8123.94462701", 10964],
[1486512000, "988.4", "1000.1", "963.3", "987.5", "983.7", "10989.31074845", 16741],
[1486598400, "987.4", "1007.4", "847.9", "926.4", "934.5", "22530.11626076", 52668],
[1486684800, "926.4", "949.0", "886.0", "939.7", "916.7", "11173.53504917", 12588],
],
"last": 1548288000
}
}
I get
KeyError: 'XXBTZEUR'
on the json_normalize line. Seems to indicate to me that json_normalize is trying to build the DF from the "XXBTZEUR" level, not lower down at the record level. How do I get json_normalize to read the records instead. ie How do I get it to reference deep enough?
I have read several other posts on this site without understanding what I'm doing wrong.
One post mentions that json.loads() must be used. Is json_string.json() also loading the JSON object or do I need the json.loads() instead?
Also tried variations of json_normalize:
BTCEUR_Daily_Table = json_normalize(json_data[[]])
TypeError: unhashable type: 'list'
Can normalize not load an array into a DF line?
code so far:
BTCEUR_Daily_URL = 'http://api.kraken.com/0/public/OHLC?pair=XXBTZEUR&interval=1440'
json_string = requests.get(BTCEUR_Daily_URL)
json_data = json_string.json()
BTCEUR_Daily_Table = json_normalize(json_data, record_path=["XXBTZEUR"])
What I need in result:
In my DF, I just want the arrayed records shown in the "body" of the JSON structure. None of the header & footer are needed.
The solution I found was:
BTCEUR_Daily_Table = json_normalize(data=json_data, record_path=[['result','XXBTZEUR']])
The 2nd parameter specifies the full "path" to the parent label of the records.
Apparently double brackets are needed to specify a full path, otherwise the 2 labels are taken to mean 2 top level names.
Without another post here, I would never have found the solution.

Split JSON into two individual JSON objects using Nifi

I have a JSON like
{
"campaign_key": 316,
"client_key": 127,
"cpn_mid_counter": "24",
"cpn_name": "Bopal",
"cpn_status": "Active",
"clt_name": "Bopal Ventures",
"clt_status": "Active"
}
Expected output
1st JSON :
{
"campaign_key": 316,
"client_key": 127,
"cpn_mid_counter": "24",
"cpn_name": "Bopal",
"cpn_status": "Active"
}
2nd JSON:
{
"clt_name": "Bopal Ventures",
"clt_status": "Active"
}
How do I acheive this by using NIFI? Thanks.
You can do what 'user' had said. The not-so-good thing about that approach is, if you number of fields are increasing, then you are required to add that many JSON Path expression attributes to EvaluateJsonPath and subsequently add that many attributes in ReplaceText.
Instead what I'm proposing is, use QueryRecord with Record Reader set to JsonTreeReader and Record Writer set to JsonRecordSetWriter. And add two dynamic relationship properties as follows:
json1 : SELECT campaign_key, client_key, cpn_mid_counter, cpn_name, cpn_status FROM FLOWFILE
json2 : SELECT clt_name, clt_status FROM FLOWFILE
This approach takes care of reading and writing the output in JSON format. Plus, if you want to add more fields, you just have add the field name in the SQL SELECT statement.
QueryRecord processor lets you execute SQL query against the FlowFile content. More details on this processor can be found here
Attaching screenshots
Karthik,
Use EvaluateJsonPath processor to get those all json Values by using its keys.
Example: $.campaign_key for gets compaign key value and $.clt_name for get clt name.
Like above one you can get all jsons.
Then use ReplaceText Processor for convert single json into two jsons.
{"Compaign_Key":${CompaignKey},...etc}
{"Clt_name":${clt_name}}
It will convert single json into two jsons.
Hope this helpful and let me know if you have issues.

How to split an array of JSON documents into fixed size chunks?

I have a JSON document representing an array of 100 objects and I need to process this document in batches, e.g. 10 objects per batch.
def text = '[{1st},{2nd},{3rd},{4th},...{100th}]'
def json = new groovy.json.JsonSlurper().parseText(text)
Now I need to take first 10 elements from text ([{1st},{2nd},..{10th}]) and post them into web service, then another 10 ([{11th},{12th}...{20th}]) and so on.
I've tried this in C# but not able to do that in Groovy.
Anyone suggest me the best way to send batches of json and every time total number of json has changed dynamically?
Groovy adds Iterable.collate(int size) method via DefaultGroovyMethods class and you can use it to split your input array into n-size chunks, e.g.
['a','b','c','d','e'].collate(3) == [['a','b','c'], ['d','e']]
Consider following example:
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
final String text = '[{"id": 1}, {"id": 2}, {"id": 3}, {"id": 4}, {"id": 5}, {"id": 6}]'
final List<Map> json = new JsonSlurper().parseText(text) as List<Map>
json.collate(2).each { part ->
final String out = JsonOutput.toJson(part)
println "Sending following JSON object: ${out}"
}
Run in Groovy web console
Here we have a JSON array of 6 objects. We parse this JSON to a List<Map> object and then we split into chunks of size 2 and prepare JSON for later execution. I used only 6 objects as an illustration, however it doesn't matter if the initial list contains 100 objects and we split into chunks of size 10 - the algorithm is the same.
It can be generalized and described in following steps:
Parse initial JSON array of objects
Split an array into chunks of size 10
Format chunk of 10 objects into JSON String
Process JSON document
The example shown above produces following output:
Sending following JSON object: [{"id":1},{"id":2}]
Sending following JSON object: [{"id":3},{"id":4}]
Sending following JSON object: [{"id":5},{"id":6}]

Nested CSV - Mule DataWeave

I have a CSV like this:
data1,data2,data3;dataa;datab;datac;datax,datay,dataz
data1,data2,data3;dataa;datab;datac;datax,datay,dataz
data1,data2,data3;dataa;datab;datac;datax,datay,dataz
I use spliter to process the records line by line, further I use splitBy "," in dataweave to convert the record to a map. But how I can do another level of split for ";" ? SplitBy doesnt allow muliple delimiters so do the CSV type in dataweave.
Ultimately, I want a JSON like this:
{
"1":"data1",
"2":"data2",
"3":{
"a":"dataa",
"b":"datab",
"c":"datac"
},
"x":"datax",
"y":"datay",
"z":"dataz "
}
Any thoughts ?
Try the following DataWeave code:
%dw 1.0
%output application/json
---
payload map {
"1": $[0],
"2": $[1],
"3": using (detail = $[2] splitBy ";") {
a: detail[1],
b: detail[2],
c: detail[3]
},
x: $[3],
y: $[4],
z: $[5]
}
Notes:
I modified the input data to separate datac and datax. Replace the ; character with , e.g.: ...;datab;datac,datax,...
I use File connector to read the CSV file, and directly process it in DataWeave transformer (do not use a Splitter)
I want to observe, that your JSON example has bad structure!
In this JSON the 4th element is an object and it hasn't a key, just value...
First of all, u should validate your end JSON.
Example of your valid JSON:
When u validate your JSON, I'll try to help in convering your CSV data to the JSON.