Reputation: 21
Need your help in transform a message like below using DataWeave 2.0.
If I have the following JSON payload of users & order. The output needed is the list of users who have orders (inner join) & the users who does not have orders. The list should not contain the users data if they have the orders which is not present in order list.
I tried with outerjoin from dataweave but that will pull the users who have an order but not present in orders list as well.
Please find the example below.
var users = [
{
"id": "1",
"name": "Jerney",
"order_id": "101",
},
{
"id": "2",
"name": "Marty"
"order_id": "102",
},
{
"id": "3",
"name": "Marty"
}
]
var orders = [
{
"order_id": "101",
"product": "bread"
},
{
"order_id": "104",
"product": "broccoli"
}
]
The output needed is
[
{
"id": "1",
"name": "Jerney",
"order_id": "101",
"product": "bread"
}
{
"id": "3",
"name": "Marty"
}
]
I hope example clears the expected output. I tried filtering (like outer join) but it will include the order id 102 as well in the input.
Thanks for your help!
Upvotes: 1
Views: 535
Reputation:
I suggest the following (explanations are embedded in the code):
%dw 2.0
output application/json
var users = [
{
"id": "1",
"name": "Jerney",
"order_id": "101",
},
{
"id": "2",
"name": "Marty",
"order_id": "102",
},
{
"id": "3",
"name": "Marty"
}
]
var orders = [
{
"order_id": "101",
"product": "bread"
},
{
"order_id": "104",
"product": "broccoli"
}
]
import leftJoin from dw::core::Arrays
---
// Do a left outer join to get all data from the users in the output
leftJoin(
users,
orders,
(u) -> u.order_id default "",
(o) -> o.order_id default ""
)
// Iterate over the data and via pattern matching detect:
// 1. whether you have data in the l and the r nodes where
// you concatenate them and add them to the results
// 2. whether a sole l node has an order_id fields where
// you add them to the result
// 3. throw aways all else
reduce (e,acc=[]) -> e match {
case node if (node.l? and node.r?) -> acc + (node.l ++ node.r - "orderBy")
case node if (node.l.order_id?) -> acc + node.l
else node -> acc
}
Upvotes: 1
Reputation: 25782
I found a way to achieve that but I had some strange issue in my test with the missing an order_id in the join, even after filtering it. I used an extra map to workaround. It should not be needed. This script returns exactly your desired output.
%dw 2.0
output application/json
import * from dw::core::Arrays
var users = [
{
"id": "1",
"name": "Jerney",
"order_id": "101"
},
{
"id": "2",
"name": "Marty",
"order_id": "102"
},
{
"id": "3",
"name": "Marty"
}
]
var orders = [
{
"order_id": "101",
"product": "bread"
},
{
"order_id": "104",
"product": "broccoli"
}
]
fun getUserWithOrders(users) = (users filter $.order_id?)
map ($ mapObject ($$):$) // for some reason had to add this to avoid a null error in the join
fun getUserWithoutOrders(users) = (users filter not $.order_id?)
---
join(getUserWithOrders(users), orders, (u) -> u.order_id, (o) -> o.order_id)
map ($.l ++ {product: $.r.product})
++ getUserWithoutOrders(users)
Upvotes: 1