Mule 4 - How to combine arrays inside a nested array with the same id field into one - arrays

Suppose I have the following payload with nested array, how do I combine the array inside the nested array for the same externalId as well as some logic on certain field like
shipQty - this field will be sum or add up for records with the same externalId under fillingOrder
serialNumbers - all the records under serialNumbers will be display together if the externalId is same
Kindly refer below for the input and expected output
Json Payload Input
{
"Identifier": "9i098p-898j-67586k",
"transactionDate": "2019-09-08T10:01:00-04:00",
"order": [
{
"orderNumber": "123456789",
"CourierOrderId": "1300-88-2525",
"fillingOrder": [
{
"numberOfBoxes": 0,
"tracking": [
{
"carrier": "Orange",
"trackNum": "3333444",
"trackUrl": "https://www.orange.com/track/status",
"shipDate": "2019-09-08T10:01:00-04:00",
"SerialNumber": "00000123"
}
],
"row": [
{
"externalId": "1",
"unitNo": "OP04-123456-789",
"shipQty": 2,
"serialNumbers": [
{
"serialNumber": "USD333555",
"quantity": 1
},
{
"serialNumber": "USD235678",
"quantity": 1
}
]
}
]
},
{
"tracking": [
{
"carrier": "Apple",
"trackNum": "555666",
"trackUrl": "https://www.apple.com/track/status",
"shipDate": "2019-09-08T10:01:00-04:00",
"SerialNumber": "00000645"
}
],
"row": [
{
"externalId": "1",
"unitNo": "OP04-123456-789",
"shipQty": 3,
"serialNumbers": [
{
"serialNumber": "USD123456",
"quantity": 1
},
{
"serialNumber": "USD98765",
"quantity": 1
},
{
"serialNumber": "USD45689",
"quantity": 1
}
]
}
]
},
{
"tracking": [
{
"carrier": "banana",
"trackNum": "587390",
"trackUrl": "https://www.banana.com/track/status",
"shipDate": "2019-09-08T10:01:00-04:00",
"SerialNumber": "00000365"
}
],
"row": [
{
"externalId": "2",
"unitNo": "OP05-123456-111",
"shipQty": 2,
"serialNumbers": [
{
"serialNumber": "USD00045",
"quantity": 1
},
{
"serialNumber": "USD00046",
"quantity": 1
}
]
}
]
}
]
}
]
}
Expected Json Output
{
"row": [
{
"externalId": "1",
"unitNo": "OP04-123456-789",
"shipQty": 5, //the shipQty should be add up when the externalId is same
"serialNumbers": [ //the serialNumbers should display all the data inside the serialNumbers when the externalId is same
{
"serialNumber": "USD333555",
"quantity": 1
},
{
"serialNumber": "USD235678",
"quantity": 1
},
{
"serialNumber": "USD123456",
"quantity": 1
},
{
"serialNumber": "USD98765",
"quantity": 1
},
{
"serialNumber": "USD45689",
"quantity": 1
}
]
},
{
"externalId": "2",
"unitNo": "OP05-123456-111",
"shipQty": 2,
"serialNumbers": [
{
"serialNumber": "USD00045",
"quantity": 1
},
{
"serialNumber": "USD00046",
"quantity": 1
}
}
]
}

It looks like you only need the data of "row" inside the fillingOrder field of your payload. So first thing to simplicy the problem is to get all the rows as a single array. Once you have that them you just need to group that by external id and the problem will start to look smaller.
%dw 2.0
output application/json
//First get all rows since it looks like you only need them.
//If you find this confusing try to use flatten with some simpler payloads.
var allRows = flatten(flatten(payload.order.fillingOrder).row)
//Group them according to external id.
var groupedExtId = allRows groupBy $.externalId
---
{
row: groupedExtId pluck ((value, extId, index) -> do {
var sumShipQuant = sum(value.shipQty default [])
---
{
externalId: (extId), //the key after grouping is external id
unitNo: value.unitNo[0], //assuming it is same across diff external id
shipQty: sumShipQuant,
serialNumbers: flatten(value.serialNumbers) //Flatten because value is an array and it has multiple serielNumbers array
}
})
}

This should help. I took some inspiration from Harshank Bansal post
%dw 2.0
output application/json
var groupFlat = flatten(flatten (payload.order.fillingOrder).row) groupBy ($.externalId)
---
row: [groupFlat mapObject ((value, key, index) -> {
externalId: value.externalId[0],
unitNO: value.unitNo[0],
shipQty: sum(value.shipQty),
serialNumbers: flatten(value.serialNumbers)
})]

Try this:
%dw 2.0
output application/json
---
row:[ if (payload..order..row..externalId[0] == payload..order..row..externalId[1]) {
externalId : payload..order..row..externalId[0],
unitNo: payload..order..row..unitNo[0],
shipQty: payload..order..row..shipQty[0] + payload..order..row..shipQty[1],
serialNumbers: flatten (payload..order..row..serialNumbers)
}
else null]

Related

How to filter a nested array of dictionaries with multiple conditions from another array in Swift

sample json data is this:
{
"variations": [
{
"variation_id": 391,
"name": "Fruit Shake - Chocolate, S",
"price": 10,
"attribute": [
{
"attribute_key": "pa_flavor",
"name": "Flavor",
"option": "Chocolate"
},
{
"attribute_key": "pa_size",
"name": "Size",
"option": "S"
}
]
},
{
"variation_id": 385,
"name": "Fruit Shake - Banana, L",
"price": 18,
"attribute": [
{
"attribute_key": "pa_flavor",
"name": "Flavor",
"option": "Banana"
},
{
"attribute_key": "pa_size",
"name": "Size",
"option": "L"
}
]
},
{
"variation_id": 386,
"name": "Fruit Shake - Banana, M",
"price": 15,
"attribute": [
{
"attribute_key": "pa_flavor",
"name": "Flavor",
"option": "Banana"
},
{
"attribute_key": "pa_size",
"name": "Size",
"option": "M"
}
]
}
]
}
my problem is, getting the variation_id where 2 or more attributes matches the array of string.
for example, chosenProduct = ["Banana", "L"]
I tried filter and contains but theres no way to match the other item from chosenProduct.
If I added the next condition, it returns nil
You can try this:
let varID = product.variations?.filter { att in
var matchedAttributes = 0
for thisAttribute in att.attribute {
if chosenProduct.contains(where: {$0 == thisAttribute.option}) {
matchedAttributes += 1
}
}
if matchedAttributes >= 2 {
return true
}
return false
}
Let me know if there's any doubt.
You can try this :
var chosenProduct = ["Banana","L"]
var expectedIds : [Int] = [Int]()
datas.variations?.map{ val in
val.attribute.map({ val2 in
let filtered = val2.enumerated().filter({chosenProduct.contains($0.element.option!)})
if filtered.count == chosenProduct.count{
expectedIds.append(val.variation_id!)
}
})
}
print(expectedIds) // [385]
I put the id's in array because of if you want to change your chosenProcudt example "Banana" (count 1 ). This mapping must be return variation_id like [385,386]
You can a method to Variation to make things easier:
extension Variation {
func attributesMatching(options: [String]) -> [Attribute] {
attribute.filter { options.contains($0.option) }
}
}
Then, you can just write:
let filtered = product.variations.filter { $0.attributesMatching(options: chosenProductOptions).count >= 2 }
print(filtered.map { $0.variationID })

Array within Element within Array in Variant

How can I get the data out of this array stored in a variant column in Snowflake. I don't care if it's a new table, a view or a query. There is a second column of type varchar(256) that contains a unique ID.
If you can just help me read the "confirmed" data and the "editorIds" data I can probably take it from there. Many thanks!
Output example would be
UniqueID ConfirmationID EditorID
u3kd9 xxxx-436a-a2d7 nupd
u3kd9 xxxx-436a-a2d7 9l34c
R3nDo xxxx-436a-a3e4 5rnj
yP48a xxxx-436a-a477 jTpz8
yP48a xxxx-436a-a477 nupd
[
{
"confirmed": {
"Confirmation": "Entry ID=xxxx-436a-a2d7-3525158332f0: Confirmed order submitted.",
"ConfirmationID": "xxxx-436a-a2d7-3525158332f0",
"ConfirmedOrders": 1,
"Received": "8/29/2019 4:31:11 PM Central Time"
},
"editorIds": [
"xxsJYgWDENLoX",
"JR9bWcGwbaymm3a8v",
"JxncJrdpeFJeWsTbT"
] ,
"id": "xxxxx5AvGgeSHy8Ms6Ytyc-1",
"messages": [],
"orderJson": {
"EntryID": "xxxxx5AvGgeSHy8Ms6Ytyc-1",
"Orders": [
{
"DropShipFlag": 1,
"FromAddressValue": 1,
"OrderAttributes": [
{
"AttributeUID": 548
},
{
"AttributeUID": 553
},
{
"AttributeUID": 2418
}
],
"OrderItems": [
{
"EditorId": "aC3f5HsJYgWDENLoX",
"ItemAssets": [
{
"AssetPath": "https://xxxx573043eac521.png",
"DP2NodeID": "10000",
"ImageHash": "000000000000000FFFFFFFFFFFFFFFFF",
"ImageRotation": 0,
"OffsetX": 50,
"OffsetY": 50,
"PrintedFileName": "aC3f5HsJYgWDENLoX-10000",
"X": 50,
"Y": 52.03909266409266,
"ZoomX": 100,
"ZoomY": 93.75
}
],
"ItemAttributes": [
{
"AttributeUID": 2105
},
{
"AttributeUID": 125
}
],
"ItemBookAttribute": null,
"ProductUID": 52,
"Quantity": 1
}
],
"SendNotificationEmailToAccount": true,
"SequenceNumber": 1,
"ShipToAddress": {
"Addr1": "Addr1",
"Addr2": "0",
"City": "City",
"Country": "US",
"Name": "Name",
"State": "ST",
"Zip": "00000"
}
}
]
},
"orderNumber": null,
"status": "order_placed",
"submitted": {
"Account": "350000",
"ConfirmationID": "xxxxx-436a-a2d7-3525158332f0",
"EntryID": "xxxxx-5AvGgeSHy8Ms6Ytyc-1",
"Key": "D83590AFF0CC0000B54B",
"NumberOfOrders": 1,
"Orders": [
{
"LineItems": [],
"Note": "",
"Products": [
{
"Price": "00.30",
"ProductDescription": "xxxxxint 8x10",
"Quantity": 1
},
{
"Price": "00.40",
"ProductDescription": "xxxxxut Black 8x10",
"Quantity": 1
},
{
"Price": "00.50",
"ProductDescription": "xxxxx"
},
{
"Price": "00.50",
"ProductDescription": "xxxscount",
"Quantity": 1
}
],
"SequenceNumber": "1",
"SubTotal": "00.70",
"Tax": "1.01",
"Total": "00.71"
}
],
"Received": "8/29/2019 4:31:10 PM Central Time"
},
"tracking": null,
"updatedOn": 1.598736670503000e+12
}
]
So, this is how I'd query that exact JSON assuming the data is in column var in table x:
SELECT x.var[0]:confirmed:ConfirmationID::varchar as ConfirmationID,
f.value::varchar as EditorID
FROM x,
LATERAL FLATTEN(input => var[0]:editorIds) f
;
Since your sample output doesn't match the JSON that you provided, I will assume that this is what you need.
Also, as a note, your JSON includes outer [ ] which indicates that the entire JSON string is inside an array. This is the reason for var[0] in my query. If you have multiple records inside that array, then you should remove that. In general, you should exclude those and instead load each record into the table separately. I wasn't sure whether you could make that change, so I just wanted to make note.

Querying array in hazelcast jsonvalues

I am trying to search HazelcastJsonValue, data example for the same.
class A {
B[] listOfB;
}
class B {
int num;
String name;
}
'A' object is present in Hazelcast as HazelcastJsonValue and i want to create query which fetches all objects which contain B for which num = 10 and name = test
hazelcast query for array search using predicate
Predicate.equal("listOfB[any].name","test")
for above scenario query i can make using predicates
Predicate[] arrayOfPredicate = {Predicates.equal("listOfB[any].num",10)
,Predicates.equal("listOfB[any].name","test")};
Predicate p = Predicates.and(arrayOfPredicate);
System.out.println(p.toString()); // (listOfB[any].num=10 AND listOfB[any].name=test)
Example Data in hazelcast
[
{
"listOfB": [
{
"num": 10,
"name": "ab"
},
{
"num": 11,
"name": "test"
}
]
},
{
"listOfB": [
{
"num": 10,
"name": "test"
},
{
"num": 12,
"name": "xyz"
}
]
},
{
"listOfB": [
{
"num": 30,
"name": "abc"
}
]
}
]
Hazelcast query for same
(listOfB[any].num=10 AND listOfB[any].name=test)
But this is not giving desired results instead below result came
[
{
"listOfB": [
{
"num": 10,
"name": "ab"
},
{
"num": 11,
"name": "test"
}
]
},
{
"listOfB": [
{
"num": 10,
"name": "test"
},
{
"num": 12,
"name": "xyz"
}
]
}
]
Desired results are
{
"listOfB": [
{
"num": 10,
"name": "test"
},
{
"num": 12,
"name": "xyz"
}
]
}
How can i get desired results?
Both of the above should've been returned in your result set. Is this not the case? The fact that you're wanting any will return true for the above data. If you limited the filter to listOfB[0], then the 2nd will be returned but I'm sure your intention is to not limit to 1st item only.

Avoid empty array elements in mongo db

How to avoid empty array while filtering results while querying a collection in MongoDb
[
{
"_id": ObjectId("5d429786bd7b5f4ae4a64790"),
"extensions": {
"outcome": "success",
"docType": "ABC",
"Roll No": "1"
},
"data": [
{
"Page1": [
{
"heading": "LIST",
"content": [
{
"text": "<b>12345</b>"
},
],
}
],
"highlights": [
{
"name": "ABCD",
"text": "EFGH",
}
],
"marks": [
{
"revision": "revision 1",
"Score": [
{
"maths": "100",
"science": "40",
"history": "90"
},
{
"lab1": "25",
"lab2": "25"
}
],
"Result": "Pass"
},
{
"revision": "revision 1",
"Score": [
{
"maths": "100",
"science": "40"
},
{
"lab1": "25",
"lab2": "25"
}
],
"Result": "Pass"
}
]
}
]
}
]
I am looking for results that has only "history" marks in the score array.
I tried the following query (in mongo 3.6.10) but it returns empty score array as well the array that has history as well
db.getCollection('student_scores').find({
"data.marks.score.history": {
$not: {
$type: 10
},
$exists: true
}
},
{
"extensions.rollNo": 1,
"data.marks.score.history": 1
})
Desired output is
{
"extensions": {
"rollNo": "1"
},
"data": [
{
"marks": [
{
"Score": [
{
"history": "90"
}
]
}
]
}
]
}
I used something like the following;
db.getCollection('student_scores').aggregate([
{
$unwind: "$data"
},
{
$unwind: "$data.marks"
},
{
$unwind: "$data.marks.Score"
},
{
$match: {
"data.marks.Score.history": {
$exists: true,
$not: {
$type: 10
}
}
}
},
{
$project: {
"extensions.Roll No": 1,
"data.marks.Score.history": 1
}
},
{
$group: {
_id: "$extensions.Roll No",
history_grades: {
$push: "$data.marks.Score.history"
}
}
}
])
where I got the following result with your input (I think more readable than your expected output);
[
{
"_id": "1",
"history_grades": [
"90"
]
}
]
where _id represents "extensions.Roll No" value for any given data set.
What do you think?
check with a bigger input on mongoplayground
OK, so I still think the data design here with the Score array is a little off but here is solution that will ensure that a Score array contains only 1 entry and that entry is for a key of history. We use dotpath array diving as a trick to get to the value of history.
c = db.foo.aggregate([
{$unwind: "$data"}
,{$unwind: "$data.marks"}
,{$project: {
result: {$cond: [
{$and: [ // if
{$eq: [1, {$size: "$data.marks.Score"}]}, // Only 1 item...
// A little trick! $data.marks.Score.history will resolve to an *array*
// of the values associated with each object in $data.marks.Score (the parent
// array) having a key of history. BUT: As it resolves, if there is no
// field for that key, nothing is added to resolution vector -- not even a null.
// This means the resolved array could
// be **shorter** than the input. FOr example:
// > db.foo.insert({"x":[ {b:2}, {a:3,b:4}, {b:7}, {a:99} ]});
// WriteResult({ "nInserted" : 1 })
// > db.foo.aggregate([ {$project: {z: "$x.b", n: {$size: "$x.b"}} } ]);
// { "z" : [ 2, 4, 7 ], "n" : 3 }
// > db.foo.aggregate([ {$project: {z: "$x.a", n: {$size: "$x.a"}} } ]);
// { "z" : [ 3, 99 ], "n" : 2 }
//
// You must be careful about this.
// But we also know this resolved vector is of size 1 (see above) so we can go ahead and grab
// the 0th item and that becomes our output.
// Note that if we did not have the requirement of ONLY history, then we would not
// need the fancy $cond thing.
{$arrayElemAt: ["$data.marks.Score.history",0]}
]},
{$arrayElemAt: ["$data.marks.Score.history",0]}, // then (use value of history)
null ] } // else set null
,extensions: "$extensions" // just carry over extensions
}}
,{$match: {"result": {$ne: null} }} // only take good ones.

jsonb query in postgres

I've a table in postgres named: op_user_event_data, which has a column named data, where I store a jsonb, and what I have at the moment is a json like this:
{
"aisles": [],
"taskGroups": [
{
"index": 0,
"tasks": [
{
"index": 1,
"mandatory": false,
"name": "Dados de Linear",
"structuresType": null,
"lines": [
{
"sku": {
"skuId": 1,
"skuName": "Limiano Bola",
"marketId": [
1,
3,
10,
17
],
"productId": 15,
"brandId": [
38,
44
]
},
"taskLineFields": [
{
"tcv": {
"value": "2126474"
},
"columnType": "skuLocalCode",
"columnId": 99
},
{
"tcv": {
"value": null
},
"columnType": "face",
"columnId": 29
},
]
},
{
"sku": {
"skuId": 3,
"skuName": "Limiano Bolinha",
"marketId": [
1,
3,
10,
17
],
"productId": 15,
"brandId": [
38,
44
]
},
"taskLineFields": [
{
"tcv": {
"value": "2545842"
},
"columnType": "skuLocalCode",
"columnId": 99
},
{
"tcv": {
"value": null
},
"columnType": "face",
"columnId": 29
},
]
},
{
"sku": {
"skuId": 5,
"skuName": "Limiano Bola 1/2",
"marketId": [
1,
3,
10,
17
],
"productId": 15,
"brandId": [
38,
44
]
},
"taskLineFields": [
{
"tcv": {
"value": "5127450"
},
"columnType": "skuLocalCode",
"columnId": 99
},
{
"tcv": {
"value": "5.89"
},
"columnType": "rsp",
"columnId": 33
}
]
}
Basically I've an object which has
Aisles [],
taskGroups,
id and name.
Inside the taskGroups as shown in the json, one of the atributes is tasks which is an array, that also have an array called lines which have an array of sku and tasklines.
Basically:
taskGroups -> tasks -> lines -> sku or taskLineFields.
I've tried different queries to get the sku but when I try to get anything further than 'lines' it just came as blank or in some other tries 'cannot call elements from scalar'
Can anyone help me with this issue? Note this is just a sample json.
Anyone knows how make this to work:
I Want all lines where lines->taskLineFields->columnType = 'offer'
All I can do is this, but throwing error on scalar:
SELECT lines->'sku' Produto, lines->'taskLineFields'->'tcv'->>'value' ValorOferta
FROM sd_bel.op_user_event_data,
jsonb_array_elements(data->'taskGroups') taskgroups,
jsonb_array_elements(taskgroups->'tasks') tasks,
jsonb_array_elements(tasks->'columns') columns,
jsonb_array_elements(tasks->'lines') lines
WHERE created_by = 'belteste'
AND lines->'taskLineFields'->>'columnType' = 'offer'
say your data is in some json_column in your table
with t as (
select json_column as xyz from table
),
tg as ( select json_array_elements(xyz->'taskGroups') taskgroups from t),
tsk as (select json_array_elements(taskgroups->'tasks') tasks from tg)
select json_array_elements(tasks->'lines') -> 'sku' as sku from tsk;

Resources