Compare strings with Array of Strings Mule 4 - mule

I have to compare/exactly match one String against an array of String.
Input:
{
"country": "India",
"countries": "India,Russia,USA"
}
Output:
If country matches from the List present in countries then Return True, if not then return False.

It usually makes sense to separate your problem, in this case in two parts
Parse the list of countries as a list
Check whether your country is present or not
For 1 you can use something like splitBy. And then for 2 you can use contains.
So, you can do something like:
%dw 2.0
output application/json
fun check(p) = do {
var countries = splitBy(p.countries, ",")
---
contains(countries, p.country)
}
---
check(payload)

%dw 2.0
output application/json
payload.countries contains payload.country

contains could be used to check whether the substring (country) is present in available string (list of countries).
However, It would return true even if an incomplete substring like "Ind" is provided for country as technically the substring is present in the available countries string.
So, splitBy could be used to split the available string (countries) to individual substrings and checked with the country substring.
%dw 2.0
output application/json
---
payload.countries splitBy(",") contains payload.country

Related

enrich one JSON array with data from another based on multiple conditions using dataweave 2.0

Recently, I asked this question about filter and merge two JSONs based on multiple conditions.
However, now I need mongo variable to be enriched with mysql variable data. If conditions
mongo.NUM_CONTROL = mysql.DOCNUM
mongo.NUM_ITEM = mysql.LIN_NUM_ITEM
do not match, each mongo element stays the same. But if they match, each mongo element must be enriched with mysql equivalent item.
You can use the following dataweave expression:
%dw 2.0
import * from dw::core::Arrays
output application/json
---
leftJoin(mongo, mysql, (m) -> m.NUM_CONTROL ++ "_" ++ m.NUM_ITEM, (s) -> s.DOCNUM ++ "_" ++ s.LIN_NUM_ITEM) map (item, index) ->
item.l ++ (if (item.r != null) item.r else {})
In order to left join two arrays, a common key field is needed. In this case, based on your scenario, the common keys corresponds to:
mongo: NUM_CONTROL and NUM_ITEM
mysql: DOCNUM and LIN_NUM_ITEM
So, concatenating mongo.NUM_CONTROL with mysql.NUM_ITEM will give the unique record key for mongo, and concatenating mysql.DOCNUM and mysql.LIN_NUM_ITEM will give the unique record key for mysql. Now those calculated keys can be used to left join the arrays. Using an underscore character (or whatever other non numeric character like a pipe, for example) as a separator will make sure that the correct records will be matched (if you have a mongo record with NUM_CONTROL = 1 and NUM_ITEM = 11 and a mysql record with DOCNUM = 11 and LIN_NUM_ITEM = 1, without the separator you would have the same calculated key value for mongo and mysql (111) and they would be joined incorrectly. With the separator, this won't happen as the mongo calculated key would be 1_11 and mysql calculated key 11_1).

Best way to manage and manipulate large sql queries in Mule

I have a requirement to run a large sql query in mule, but the query changes based on the payload. I have to modify the column names, the where and group by conditions etc based on the payload.
Currently I place a template query in resources folder say test.sql. And in the query I place some keyword to be replaced like "replaceColumn". And I use a set variable component to replace that keyword with required keyword like "Field1Column"
variable: formQuery
%dw 2.0
output application/java
var query = readUrl('classpath://test.sql','text/plain')
---
query replace "replaceColumn" with payload.Field1Column
In the DB select component I simply put #[vars.formQuery]
This solution works for me, but gets difficult to replace many parts of the query by nesting the replace operator.
What is a good way to do it?
You can do this recursive replace based on map with key/values as described here https://simpleflatservice.com/mule4/RecursiveReplaceByMap.html
%dw 2.0
var x="The quick brown fox jumps over the lazy dog"
var myMap={fox:'chicken', dog:"me"}
var keys=myMap pluck ($$)
fun changeMe ( value, index ) =
if ( index < sizeOf(keys) )
changeMe( (value replace ( keys[index] ) with ( myMap[keys[index]] ) ) , index+1 )
else value
output application/json
---
changeMe(x,0)
output
"The quick brown chicken jumps over the lazy me"

Sum function in mule dataweave takes too much time

I have one ArrayList which contains more than 45,000 records. I want to create a new List which will contain Sum of all values when combination of ID and Name value present in the list. e.g. Below is my input List. I am creating this list by reading xls file and storing it in one variable called "myList" -
[
{ID=481, name =ABCD, value=100},
{ID=481, name =ABCD, value=50},
{ID=2053, name =XYZ, value=300}
]
My Code -
%dw 1.0
%output application/java
%function getIdname(ID, name) (ID ++ " - " ++ name)
%function addAllValues(ID, name) sum ((flowVars.myList.Data filter (getIdname($.ID,$.name) == getIdname(ID, name))).value)
---
{
Data: flowVars.myList.Data map ((payload01 , indexOfPayload01) -> {
ID: payload01.ID,
name: payload01.name,
finaValue : addAllValues(payload01.ID, payload01.name)
})
}
Output -
Data=[
{ID=481, name =ABCD, finalValue=150},
{ID=2053, name =XYZ, finalValue=300}
]
Here, I am getting desired output as above for a file with 5 or 10 records. But, if I am using actual file with more than 45,000 records it is taking too much time to execute my code and it is not creating any output. Also, I am not getting any exception. Can anyone suggest what I am doing wrong here. Why it is taking so much time to sum equal records. I have checked it for 40 mins, but still not received any output
You are filtering 45000 records in every single iteration of the map which is causing this delay (i.e. you are filtering 45000 times). You have to filter/group only once. Also your dataweave will not produce the output you want because there is no distinctBy used.
Instead try this:
%dw 1.0
%output application/java
%var dataByIdName = flowVars.myList.Data groupBy ($.ID ++ $.name)
---
{
Data: dataByIdName map {
ID: $[0].ID,
name: $[0].name,
finalValue: sum $.*value
}
}
This doesn't need distinctBy and also you only group once.

using regex group in dataweave mule

how can I use regex groups to extract data from a string in dataweave 1.0?
%var sampleString="3,2,0"
{
"groups":using(regexMatch= sampleString scan /^(?<grp1>\d{1}),(?<grp2>\d{1}),(?<grp3>\d{1})$/) {
"group1": regexMatch["grp1"] ????? Any way to get the grp1 value by group name,
"group2": regexMatch[0][2] //works,
"group3": regexMatch[0][3] //works
}
}
Unfortunately the scan function returns an array of arrays (doco), not an array of maps, so the only way you can interrogate it is via numeric index. Named capturing groups are treated as any other group in the end (i.e. the name is ignored).

query using string in PyTables 3

I have a table:
h5file=open_file("ex.h5", "w")
class ex(IsDescription):
A=StringCol(5, pos=0)
B=StringCol(5, pos=1)
C=StringCol(5, pos=2)
table=h5file.create_table('/', 'table', ex, "Passing string as column name")
table=h5file.root.table
rows=[
('abc', 'bcd', 'dse'),
('der', 'fre', 'swr'),
('xsd', 'weq', 'rty')
]
table.append(rows)
table.flush()
I am trying to query as per below:
find='swr'
creteria='B'
if creteria=='B':
condition='B'
else:
condition='C'
value=[x['A'] for x in table.where("""condition==find""")]
print(value)
It returns:
ValueError: there are no columns taking part in condition condition==find
Is there a way to use condition as a column name in above query?
Thanks in advance.
Yes, you can use Pytables .where() to search based on a condition. The problem is how you constructed your query for the table.where(condition). See Note about strings under Table.where() in the Pytables Users Guide:
A special care should be taken when the query condition includes string literals. ... Python 3 strings are unicode objects.
in Python 3, “condition” should be defined like this:
condition = 'col1 == b"AAAA"'
The reason is that in Python 3 “condition” implies a comparison between a string of bytes (“col1” contents) and an unicode literal (“AAAA”).
The simplest form of your query is shown below. It returns a subset of rows that match the condition. Note use of single and double quotes for string and unicode:
query_table = table.where('C=="swr"') # search in column C
I rewrote your example as best I could. See below. It shows several ways to enter the condition. I'm not smart enough to figure out how to combine your creteria and find variables into a single condition variable with string and unicode characters.
from tables import *
class ex(IsDescription):
A=StringCol(5, pos=0)
B=StringCol(5, pos=1)
C=StringCol(5, pos=2)
h5file=open_file("ex.h5", "w")
table=h5file.create_table('/', 'table', ex, "Passing string as column name")
## table=h5file.root.table
rows=[
('abc', 'bcd', 'dse'),
('der', 'fre', 'swr'),
('xsd', 'weq', 'rty')
]
table.append(rows)
table.flush()
find='swr'
query_table = table.where('C==find')
for row in query_table :
print (row)
print (row['A'], row['B'], row['C'])
value=[x['A'] for x in table.where('C == "swr"')]
print(value)
value=[x['A'] for x in table.where('C == find')]
print(value)
h5file.close()
Output shown below:
/table.row (Row), pointing to row #1
b'der' b'fre' b'swr'
[b'der']
[b'der']