Convert CSV based on the filtering condition - mulesoft

Could some one please help me to map the below csv to JSON.
Need to filter based on the below filtering condition on all the five fields.
Integer
Length 5 digits
First two digits starts with “65”
Input:
field1,field2,field3,field4,field5
123,ABC12,4512300000,234,567
567,4532100000,DEF34,123,432
Output:
[
{
"OrderNUmber": "4512300000"
},
{
"OrderNUmber": "4532100000"
}
]

I am think that there will be just one field in each row that matches all three conditions, hence selector [0]
%dw 2.0
output application/json
import * from dw::Runtime
fun isNumber(value): Boolean = try(() -> isInteger(value)) orElse false
---
payload map ((item, index) ->
OrderNumber: (valuesOf(item)
filter (( value ) -> (isNumber(value)
and (value startsWith "65")
and sizeOf(value) == 5)))[0])

Related

dataweave filter and maxBy on nested array list

I have a list of students and their marks for respective subjects. I want to filter all students of a specific grades and then find the student who got maximum marks in a specific object.
[
{
"name": "User 01",
"grade": 1,
"schoolName": "school01",
"marks": {
"english": 10,
"math": 30,
"social": 30
}
},
{
"name": "User 02",
"grade": 1,
"schoolName": "school02",
"marks": {
"english": 10,
"math": 20,
"social": 30
}
}
]
I am able to perform both the operations independently. can someone help me find the student object who got max marks in math in a specific grade.
If I understand your requirement correctly this script does it. Just change the variables grade and topic to the specific values you are interested in.
Generally speaking it is always better to provide example outputs and whatever you got as script to understand better the context, in addition to the input samples.
%dw 2.0
output application/json
var grade = 1
var topic = "math"
---
flatten(
payload map (alumn, order) ->
(alumn.marks pluck ((value, key, index) ->
{
name: alumn.name,
grade: alumn.grade,
result:value,
topic: key
})
)
) // restructure the list to one result per element
filter ((item, index) -> (item.grade == grade)) // filter by grade
maxBy ((item) -> item.result) // get the maximum result
I used it below to achieve it.
%dw 2.0
output application/json
var grade = 1
var topic = "math"
---
payload filter (
((item, index) -> item.grade == grade)
) maxBy ($.marks.math as String {format: "000000"})

Groovy dictionary map - how to sort according to a map's key's value - if the value is in x.x.x.x format - numberically sort version value with . char

I have the following dictionary aka MAP in Groovy.
list = [
[
name:ProductA-manifest-file.json,
path:ProductA,
properties: [
[
key:release,
value:RC1.0
],
[ key:PIPELINE_VERSION,
value:1.0.0.11
]
],
repo:some-generic-repo-local,
],
[
name:ProductA-manifest-file.json,
path:ProductA,
properties: [
[
key:release,
value:RC1.0
],
[ key:PIPELINE_VERSION,
value:1.0.0.75
]
],
repo:some-generic-repo-local,
],
[
name:ProductA-manifest-file.json,
path:ProductA,
properties: [
[
key:release,
value:RC1.0
],
[ key:PIPELINE_VERSION,
value:1.0.0.1104
]
],
repo:some-generic-repo-local,
],
[
more similar entries here containing
],
[
more similar entries here
]
]
I'm trying to sort this map acc. to properties's key = PIPELINE_VERSION's value which is in the format of x.x.x.x i.e. 4 digit set case.
I tried the following command but it's not giving me the entry which contains 1.0.0.1104 as PIPELINE_VERSION. It's giving me 1.0.0.75 (which seems like some kind of string type sort.
// Sort the list entries acc. to pipeline version
def sortedList = list.sort { it.properties.PIPELINE_VERSION.value }
println "###### sortedList" + sortedList
println "\n^^^^\n"
println sortedList.last() // this should return me the entry which contains 1.0.0.1104 but I'm getting 1.0.0.75
}
Also tried using .toInteger() as def sortedList = list.sort { it.properties.PIPELINE_VERSION.toInteger().value } but that didn't work giving an error.
17:07:22 Caught: groovy.lang.MissingMethodException: No signature of method: java.util.ArrayList.toInteger() is applicable for argument types: () values: []
17:07:22 Possible solutions: toUnique(), toUnique()
17:07:22 groovy.lang.MissingMethodException: No signature of method: java.util.ArrayList.toInteger() is applicable for argument types: () values: []
17:07:22 Possible solutions: toUnique(), toUnique()
Tried:list.sort {it.value.tokenize('.').last()} that didn't do either.
Smaller example will be:
map = ['a':'1.0.0.11', d:'1.0.0.85', 'b':'1.0.0.1104', 'c':"1.0.0.75"]
println " before sorting : " + map
//map = map.sort {it.value } // this doesn't work if the value is not a pure number format aka x.x.x. format ok lets try the following
map = map.sort {it.value.tokenize('.').last()} // cool that didn't work either
println " after sorting : " + map
Questions:
How can I get the entry which has the highest PIPELINE_VERSION value?
How can I get the Nth array index entry which contains the highest PIPELINE_VERSOIN in its value.
How to handle N no. of digit set set cases? i.e. 1.0.0 or 1.2 or 1.0.0.12 or 1.4.1.9.255
Below should work (assuming the format X.X.X.X always has X as a number)
def sortClosure = { a, b ->
// Extract the pattern
def extract = {
it.properties.find { it.key == 'PIPELINE_VERSION' }?.value?.tokenize(/./)
}
// Transpose the numbers to compare
// gives [[1,1], [0,0], [0,0], [11, 1104]] for example
def transposed = [extract(a), extract(b)].transpose()
// Then compare the first occurrence of non-zero value (-1 or 1)
def compareInt = transposed.collect {
it[0].toInteger() <=> it[1].toInteger()
}.find()
compareInt ?: 0
}
list.sort(sortClosure)
This one-liner solution worked.
For the smaller example!
def versions = ['a':'1.0.0.11', d:'1.0.0.85', 'b':'1.0.0.1104', 'c':"1.0.0.75"]
map = map.sort {it.value.tokenize('.').last().toInteger() }
OK, found the shenzi(one-liner) solution for the complex structure (hint from dmahapatro's answer):
i.e. a map > containing array > containing another map for PIPELINE_VERSION.
println "\n\n before sorting : " + list
list = list.sort {it.properties.find { it.key == 'PIPELINE_VERSION' }?.value?.tokenize('.').last().toInteger() }
println " after sorting : " + list
println "\n\n The last entry which contains the sorted shenzi is: " + map.last()
NOTE: The above solution and other answers so far, will only if the PIPELINE first 3 digit sets are 1.0.0 i.e. it's only deciding the highest number based on the 4th digit set (.last()). It'd be fun to use a similar one-liner to find highest PIPELINE_VERSION which actually covers all 4 or N no. of digit sets.
def versions = ['a':'1.0.0.11', d:'1.0.0.85', 'b':'1.0.0.1104', 'c':"1.0.0.75"]
//sort:
def sorted = versions.sort{ (it.value=~/\d+|\D+/).findAll() }
result:
[a:1.0.0.11, c:1.0.0.75, d:1.0.0.85, b:1.0.0.1104]
Given this:
def map = ['a':'1.0.0.11', d:'1.0.0.85', 'b':'1.0.0.1104', 'c':"1.0.0.75"]
map = map.sort { a, b ->
compareVersion(a.value, b.value)
}
the goal becomes to write a compareVersion function that satisfies these (incomplete) tests:
assert 0 == compareVersion('1.0.0.0', '1.0.0.0')
assert 1 == compareVersion('1.1.0.0', '1.0.0.0')
assert -1 == compareVersion('1.1.0.0', '1.2.0.0')
assert 1 == compareVersion('1.1.3.0', '1.1.2.0')
assert 1 == compareVersion('1.1.4.1104', '1.1.4.11')
Here is one implementation. It's not the shortest but is quite "Groovy" in style:
//
// e.g. a = '1.0.0.11', b = '1.0.0.85'
//
def compareVersion = { a, b ->
// e.g. [1, 0, 0, 11]
def listA = a.tokenize('.').collect { it as int }
// e.g. [1, 0, 0, 85]
def listB = b.tokenize('.').collect { it as int }
// e.g. [0, 0, 0, -1]
def compareList = [listA, listB].transpose().collect { it[0] <=> it[1] }
// return first non-zero value in compareList, or 0 if there are none
compareList.inject(0) { result, item ->
(result) ?: item
}
}
Output of the original map, and sorted:
$ groovy Q.groovy
before sorting : [a:1.0.0.11, d:1.0.0.85, b:1.0.0.1104, c:1.0.0.75]
after sorting : [a:1.0.0.11, c:1.0.0.75, d:1.0.0.85, b:1.0.0.1104]

Get delta at cursor (no selection) without splitting it

Here's a delta with an attribute:
Trying to get the delta with
editor.getContents(range.index, range.length);
returns
Delta: {
ops: []
}
which is expected - range.length is 0.
Is there a way of returning the entire delta (from left to right) so it looks like this:
Delta: {
ops: [
{
attributes: { test: '123' },
insert: 'A selection'
},
...
]
}
Assuming a slightly more complex example to disambiguate and assuming the test 123 attribute is implemented with a class Attributor, given the document:
<div class="ql-editor">
<p><strong>ab</strong><span class="ql-test=123">cd<em>ef</em></span></p>
</div>
I think what you are asking however is getting the Delta for the "cdef" text when the user's cursor is between the "e" and "f" and so your range is index: 5.
This is an experimental/undocumented API but quill.scroll.path(5) will get you an array [[blockBlot, 0], [inlineBlot, 2], [italicBlot, 1]] and the blot you want in this case is the second one so by summing the offsets to it you will have 2 (0 + 2) and then you can call quill.getContents(2, blot.length()).
If the class is unique (or you can access the DOM node some other way) you can also do:
const Parchment = Quill.import("parchment");
let node = document.querySelector('.ql-test-123');
let blot = Parchment.find(node);
let offset = quill.scroll.offset(blot);
quill.getContents(offset, blot.length());

How to find a document with array size within a range in MongoDB?

Given the following document structure:
{
_id : Mongo ID,
data : [someData1, someData2, ..., someDataN]
}
I want to get all documents which data size is between a and b (strict positive integers, consider a < b is always true).
I first thought about using $size, but the Mongo doc states:
$size does not accept ranges of values. To select documents based on fields with different numbers of elements, create a counter field that you increment when you add elements to a field.
(Emphasis mine)
How to retrieve all the documents with a data array of length between a and b without using a counter?
Related but did not solve:
This answer which suggests using a counter
This question which asks how to query an internal length
and got many answers
This answer which suggests to use: { 'data.' + b : { $exists : true } } but I don't know how reliable it is and how it could apply to a range
This question about how to find documents with a minimal array length
You can use the $exists operator approach by including multiple terms in your query and building it up programmatically:
var startKey = 'data.' + (a-1);
var endKey = 'data.' + b;
var query = {};
query[startKey] = {$exists: true};
query[endKey] = {$exists: false};
db.test.find(query);
So for a=1 and b=3, for example, you end up with a query object that looks like:
{
"data.0" : {
"$exists" : true
},
"data.3" : {
"$exists" : false
}
}
The first part ensures there are at least a elements, and the second part ensures there are no more than b elements.

Return documents of which field of type array contains array in exact order

I'm having documents in MongoDB structured like this:
{ _id : 1, tokens : [ "one","two","three","four","five","six","seven" ] }
{ _id : 2, tokens : [ "two","three","four","one","one","five","eight" ] }
{ _id : 3, tokens : [ "six","three","four","five","one","five","nine" ] }
On average the documents contain token arrays with a length of 4500 items.
I need to do some sort of pattern matching, where I have arrays of tokens in exact order to match, i.e. let's say I have to find the following in exactly matching order...
["three","four","five"]
...I want my query to provide me the following documents...
{ _id : 1, tokens : [ "one","two","three","four","five","six","seven" ] }
{ _id : 3, tokens : [ "six","three","four","five","one","five","nine" ] }
I.e. both documents contain the exact order of the items I had in my array to search with.
Arrays I search with may have different lengths, ranging from 1 to 15 tokens.
I'm looking for the following:
Is this doable with MongoDB queries? I've read, and re-read and re-re-read the pretty good docs, but couldn't find a solution e.g. using $all.
Is there perhaps a better way to store tokens like this to get done what I need?
Thanks for any help.
It's going to be slow, but you can do this with a $where operator; pairing it with an $all operator to help with performance.
db.test.find({
tokens: {$all: ["three","four","five"]},
$where: function() {
var ix = -1;
// Find each occurrence of 'three' in this doc's tokens array and return
// true if it's followed by 'four' and 'five'.
do {
ix = this.tokens.indexOf('three', ix + 1);
if (ix !== -1 && ix+2 < this.tokens.length &&
this.tokens[ix+1] === 'four' && this.tokens[ix+2] === 'five') {
return true;
}
} while (ix !== -1);
return false;
}
})

Resources