How to group by a field in an object to create an array of objects? - mule

I have an input payload containing array of objects where I need to group-by id-key and form 2 arrays of objects based on id-key. See below details.
input Payload:
{
"id": {
"header_id": "460",
"id-branch": {
"branch-name": "genaral motors",
"req-name": "genaral motors",
"id-key": "0791",
"id-lines": {
"id-key": "0791",
"productId": "463"
}
},
"id-branch": {
"branch-name": "genaral motors",
"req-name": "genaral motors",
"id-key": "9692",
"id-lines": {
"id-key": "9692",
"productId": "464"
},
"id-lines": {
"id-key": "9692",
"productId": "465"
}
}
}
}
desired Ouput:
[
{
"branch-name": "genaral motors",
"req-name": "genaral motors",
"type": "dhl",
"lines-ids": "swr",
"lines": [
{
"productId": "463"
}
]
},
{
"branch-name": "genaral motors",
"req-name": "genaral motors",
"type": "dhl",
"lines-ids": "swr",
"lines": [
{
"productId": "464"
},
{
"productId": "465"
}
]
}
]
the output has to be generated as array of object which groups productId which are under same id-key.

Assuming that the keys are already grouped by product id, I used filterObject() to remove the keys that are not required, then use pluck() to pick the values into an array. After that I removed keys from each element that are not used in the output. The keys added I assumed that were literal since no indication was given.
For clarity I implemented a function to encapsulate the mapping of the lines.
%dw 2.0
output application/json
fun updateLines(x)=
x - "id-lines" ++ {lines: x.*"id-lines" map {productId: $.productId}}
---
payload.id
filterObject ((value, key, index) -> key as String == "id-branch")
pluck ($)
map (updateLines($) - "id-key" ++ { "type": "dhl", "lines-ids": "swr"})
Output:
[
{
"branch-name": "genaral motors",
"req-name": "genaral motors",
"lines": [
{
"productId": "463"
}
],
"type": "dhl",
"lines-ids": "swr"
},
{
"branch-name": "genaral motors",
"req-name": "genaral motors",
"lines": [
{
"productId": "464"
},
{
"productId": "465"
}
],
"type": "dhl",
"lines-ids": "swr"
}
]

Related

how can I loop through the payload and search within the same payload in another array with similar structure and alter matches

I have entered the payload as shown below, but I have to replace the values ​​of "labelnumber" with the similar number from the main line array with the matches "payload.lines.number = payload.notification.body.lines.number" that are inside the line array inside the notification element, can anyone help me how can we replace it.
input payload
{
"date": "2022-11-15T19:24:36.871Z",
"lines": [
{
"number": "123",
"labelnumber":"ABC",
"received": "2022-11-15T19:30:17.955Z"
},
{
"number": "456",
"labelnumber":"DFG",
"received": "2022-11-15T19:30:57.426Z"
},
{
"number": "789",
"labelnumber":"HIJ",
"received": "2022-11-15T19:31:49.042Z"
}
],
"notification":{
"body":{
"date": "2022-11-15T19:24:36.871Z",
"lines": [
{
"number": "123",
"labelnumber":"",
"received": "2022-11-15T19:30:17.955Z"
},
{
"number": "123",
"labelnumber":"",
"received": "2022-11-15T19:30:57.426Z"
},
{
"number": "456",
"labelnumber":"",
"received": "2022-11-15T19:31:49.042Z"
},
{
"number": "789",
"labelnumber":"",
"received": "2022-11-15T19:31:49.042Z"
},
{
"number": "789",
"labelnumber":"",
"received": "2022-11-15T19:31:49.042Z"
}
]
}
}
}
expected payload
{
"date": "2022-11-15T19:24:36.871Z",
"lines": [
{
"number": "123",
"labelnumber":"ABC",
"received": "2022-11-15T19:30:17.955Z"
},
{
"number": "456",
"labelnumber":"DFG",
"received": "2022-11-15T19:30:57.426Z"
},
{
"number": "789",
"labelnumber":"HIJ",
"received": "2022-11-15T19:31:49.042Z"
}
],
"notification":{
"body":{
"date": "2022-11-15T19:24:36.871Z",
"lines": [
{
"number": "123",
"labelnumber":"ABC",
"received": "2022-11-15T19:30:17.955Z"
},
{
"number": "123",
"labelnumber":"ABC",
"received": "2022-11-15T19:30:57.426Z"
},
{
"number": "456",
"labelnumber":"DFG",
"received": "2022-11-15T19:31:49.042Z"
},
{
"number": "789",
"labelnumber":"HIJ",
"received": "2022-11-15T19:31:49.042Z"
},
{
"number": "789",
"labelnumber":"HIJ",
"received": "2022-11-15T19:31:49.042Z"
}
]
}
}
}
As you can see in this example, I need to loop through the main row array and find the matches within the notification array and assign the corresponding value.
NOTE: maybe in the notification.body has many elements and I don't need to change them and I don't know the name of its elements, in this case it only has "date" but I need to keep them as they are.
With the update operator you can update only the keys that you want. This solution assumes that all the number values are defined in payload.lines.
%dw 2.0
output application/json
---
payload update {
case lines at .notification.body.lines -> lines map ((item, index) ->
item update {
case .labelnumber -> (payload.lines filter ($.number == item.number))[0].labelnumber
}
)
}
Converting reference line Array to Hashmap will help replace values efficiently instead of looping every time. Following code will work
%dw 2.0
output application/json
var lineMap = {(payload.lines map {
($.number) : $.labelnumber
})}
var modifiedLines = (payload.notification.body.lines map ((item, index) -> {
data : item mapObject ((value, key, dataindex) -> {
(key) : if (key ~= 'labelnumber') lineMap[item.number] else value
})
})).data
---
(payload - 'notification') ++
{
"notification":{
"body":{
"lines": modifiedLines
}
}
}
Update : with updated requirement body can have any fields
%dw 2.0
import * from dw::util::Values
output application/json
var lineMap = {(payload.lines map {
($.number) : $.labelnumber
})}
var modifiedLines = payload.notification.body.lines map ((item, index) -> item update 'labelnumber' with lineMap[item.number])
var body = (payload.notification.body - 'lines') ++ {lines : modifiedLines}
---
(payload - 'notification') ++
{
"notification":{
"body": body
}
}

JSON element extraction from response based on scenario outline examples or external file

This is my api response. Want to extract the value of the Id based on the displayNumber. This display number is a given in the list of values in examples/csv file.
{
"Acc": [
{
"Id": "2b765368696b3441673633325",
"code": "SGD",
"val": 406030.83,
"displayNumber": "8957",
"curval": 406030.83
},
{
"Id": "4e676269685a73787472355776764b50717a4",
"code": "GBP",
"val": 22.68,
"displayNumber": "1881",
"curval": 22.68
},
{
"Id": "526e666d65366e67626244626e6266467",
"code": "SGD",
"val": 38404.44,
"displayNumber": "1004",
"curval": 38404.44
},
],
"combinations": [
{
"displayNumber": "3444",
"Code": "SGD",
"Ids": [
{
"Id": "2b765368696b34416736333254462"
},
{
"Id": "4e676269685a7378747235577"
},
{
"Id": "526e666d65366e6762624d"
}
],
"destId": "3678434b643530456962435272d",
"curval": 3.85
},
{
"displayNumber": "8957",
"code": "SGD",
"Ids": [
{
"Id": "3678434b6435304569624357"
},
{
"Id": "4e676269685a73787472355776764b50717a4"
},
{
"Id": "526e666d65366e67626244626e62664679"
}
],
"destId": "2b765368696b344167363332544",
"curval": 406030.83
},
{
"displayNumber": "1881",
"code": "GBP",
"Ids": [
{
"Id": "3678434b643530456962435275"
},
{
"Id": "2b765368696b3441673"
},
{
"Id": "526e666d65366e67626244626e626"
}
],
"destId": "4e676269685a7378747d",
"curval": 22.68
},
]
}
Examples
|displayNumber|
|8957|
|3498|
|4943|
Below expression works if i give the value
* def tempid = response
* def fromAccount = get[0] tempid.Acc[?(#.displayNumber==8957].Id
I'm not sure how to make this comparison value (i.e. 1881) as a variable which can be read from examples (scenario outline) or a csv file. Went through the documentation, which recommends, karate filters or maps. However, not able to follow how to implement.
You almost got it :-). This is the way you want to solve this
Scenario Outline: Testing SO question for Navneeth
* def tempid = response
* def fromAccount = get[0] tempid.Acc[?(#.displayNumber == <displayNumber>)]
* print fromAccount
Examples:
|displayNumber|
|8957|
|1881|
|3444|
You need to pass the placeholder in examples as -
'<displayNumber>'

How to check a particular value on basis of condition in karate

Goal: Match the check value is correct for 123S and 123O response in API
First check the value on this location x.details[0].user.school.name[0].codeable.text if it is 123S then check if x.details[0].data.check value is abc
Then check if the value on this location x.details[1].user.school.name[0].codeable.text is 123O then check if x.details[1].data.check is xyz
The response in array inter changes it is not mandatory first element is 123S sometime API returns 123O as first array response.
Sample JSON.
{
"type": "1",
"array": 2,
"details": [
{
"path": "path",
"user": {
"school": {
"name": [
{
"value": "this is school",
"codeable": {
"details": [
{
"hello": "yty",
"condition": "check1"
}
],
"text": "123S"
}
}
]
},
"sample": "test1",
"id": "22222"
},
"data": {
"check": "abc"
}
},
{
"path": "path",
"user": {
"school": {
"name": [
{
"value": "this is school",
"codeable": {
"details": [
{
"hello": "def",
"condition": "check2"
}
],
"text": "123O"
}
}
]
},
"sample": "test",
"id": "11111"
},
"data": {
"check": "xyz"
}
}
]
}
How I did in Postman but how to replicate same in Karate?
var jsonData = pm.response.json();
pm.test("Body matches string", function () {
for(var i=0;i<jsonData.details.length;i++){
if(jsonData.details[i].user.school.name[0].codeable.text == '123S')
{
pm.expect(jsonData.details[i].data.check).to.equal('abc');
}
if(jsonData.details[i].user.school.name[0].codeable.text == '123O')
{
pm.expect(jsonData.details[i].data.check).to.equal('xyz');
}
}
});
2 lines. And this takes care of any number of combinations of lookup values :)
* def lookup = { '123S': 'abc', '123O': 'xyz' }
* match each response.details contains { data: { check: '#(lookup[_$.user.school.name[0].codeable.text])' } }

How to avoid the duplicated data entry after parsing json in kusto?

I have following sample json data.
{
"data": {
"type": "ABC",
"id": "17495500314",
"attributes": {
[!["event": "update",
"gps_vali][1]][1]d": true,
"gps": {
"distance_diff": 6.48,
"total_distance": 848.6
},
"hdop": 79,
"fuel_level": 46.8,
"total_fuel_used": 60443.9,
"location": {
"latitude": 411.372618,
"longitude": -1.254931,
"relative_position": {
"distance": "37",
}
},
"idle_periods": []
},
"relationships": {
"assets": {
"data": [
{
"type": "ABCDFTTG",
"id": "1589799143500003",
"attributes": {
"external_id": "ABCDFTTG",
"hardware_id": "ABCDFTTG"
}
}
]
},
"devices": {
"data": [
{
"type": "ABCDFTTG",
"id": "1585231172900341",
"attributes": {
"serial": "5572016191"
}
},
{
"type": "tablet",
"id": "1587893062600175",
"attributes": {
"serial": "ABCDFTTG"
}
}
]
},
"users": {
"data": [
{
"type": "user",
"id": "ABCDFTTG",
"attributes": {
"external_id": "ABCDFTTG"
}
}
]
}
}
},
"meta": {
"message_id": "11eb-8c75-0b3f87aedbb5",
"consumer_version": "1.2.0",
"origin_version": null,
"timestamp": "2021-06-14T17:42:29Z"
}
}
I want only one row instead of this two. Here is my kusto query which is used for parsing json data into table columns.
Test
|where messageId =="123"
//|mv-expand message=message.data.attributes
|mv-expand message
|mv-expand Value=message.data.relationships.assets.['data']
|mv-expand value_devices=message.data.relationships.devices.['data']
|mv-expand value_user=message.data.relationships.users.['data']
| project type=message.data.type,id=message.data.id,
event=tostring(message.data.attributes.event),
logged_at=tostring(message.data.attributes.logged_at),
distance=toint(message.data.attributes.location.relative_position.distance),
// Value=message.data.relationships.assets.['data'],//.['data']
type_asset=Value.type,asset_id=Value.id,
device_type=value_devices.type,device_id=value_devices.id,
device_attr_serial=value_devices.attributes.serial,
user_type=value_user.type,user_id=value_user.id,
user_external_id=value_user.attributes.external_id
This duplicate row appeared after adding user tag this tag is array so how to handle this array with single id.
I have parse my json data any got the following output.
Expected output should be like
check device_type and device_id columns

MuleSoft transform gives error while transforming using DWL for JSON payload

Im am new to MuleSoft.I am trying to transform a JSON payload,using transform.
I want to transform my payload as below
Input:
{
"ResponseStatus": {
"Status": "SUCCESS",
"StatusText": "SUCCESS"
},
"Processes": {
"Process": [
{
"ProcessId": "1234567",
"ProcessProperties": {
"Property": [
{
"Name": "XXXXXXXXXXX",
"Value": "11111111",
"Desc": "YYYYYYYY"
},
{
"Name": "AAAAAAAAA",
"Value": "2222222",
"Desc": "BBBBBBBB"
},
{
"Name": "QQQQQQQQQ",
"Value": "#######",
"Desc": "CCCCCCCC"
},
{
"Name": "NNNNNNN",
"Value": "IIIIIIII",
"Desc": "UYUYUYUY"
}
]
},
"EditMode": "CCCCCC",
"ProcessType": "ABCD",
"AppName": "VFVFVGBG",
"StatusHistory": {
"STS": [
{
"Sts": "COMPLETED"
}
]
}
}
]
}
}
Output:
[
{
"ProcessId": "1234567",
"AAAAAAAAA": "2222222",
"QQQQQQQQQ": "#######"
}
]
I have read DWL reference from below Mulesoft link.Also reffered this SO link.
Below is what I have tried so far,
%dw 1.0
%output application/json
---
{
"ProcessId": (payload.Processes.Process.ProcessId)[0],
AAAAAAAAA: {
(payload.Processes.Process.ProcessProperties.Property mapObject {
($.Name):$.Value when $.Name =="AAAAAAAAA" otherwise ""
})
},
QQQQQQQQQ: {
(payload.Processes.Process.ProcessProperties.Property mapObject {
($.Name):$.Value when $.Name =="QQQQQQQQQ" otherwise ""
})
}
}
I am still not able to get the desired output.
It gives me "Cannot coerce a :array to a :key"
Can anyone please help me?
The "property" json element in your input json is "Array",which it is not able to parse to a single value.
Please try below snippet and let me know if that gives your deisred o/p.
payload.Processes.Process map (
(val , index) ->
{"ProcessId":(payload.Processes.Process.ProcessId)[0]
,
(val.ProcessProperties.Property map {
(($.Name) : $.Value) when $.Name =='AAAAAAAAA' }
),
(val.ProcessProperties.Property map {
(($.Name) : $.Value) when $.Name =='QQQQQQQQQ' }
)
}
)