Search code examples
muletransformationdataweavemulesoftmule4

Mule4 Dataweave transformation


I need to transform the below JSON

Input :-

{
    "type": "donut",
    "weight-unit": "lb",
    "price-unit": "$/lb",
    "price": 10.75,
    "batters":
        {
            "batter":
                [
                    { "id": "10011", "type": "Original","weight": 500},
                    { "id": "10021", "type": "Chocolate","weight": 200, "price": 11.75 },
                    { "id": "10031", "type": "Blueberry", "weight": 250, "price": 11.75  },
                    { "id": "10041", "type": "Devil's Food", "weight": 150}
                ]
        },
    "topping":
        [
            { "id": "50011", "type": "None", "price": 0 },
            { "id": "50021", "type": "Glazed", "price": 45.23},
            { "id": "50051", "type": "Sugar", "price": 34.1},
            { "id": "50071", "type": "Powdered Sugar", "price": 21.11},
            { "id": "50061", "type": "Chocolate with Sprinkles", "price": 34.43 },
            { "id": "50031", "type": "Chocolate", "price": 87.40},
            { "id": "50041", "type": "Maple", "price": 64.11}
        ]
}

The output that I want is

Output :-

{
    "type": "donut",
    "ChocolateFlavoredGlazedDonut" : {
        "weight": 200,
        "unit": "kg",
        "price": 56.98,
        "unit": "$/kg",
    },
    "ChocolateFlavoredSprinklesDonut" : {
        "weight": 200,
        "unit": "kg",
        "price": 46.18,
        "unit": "$/kg",
    },
    "BlueberryFlavoredSugarDonut" : {
        "weight": 250,
        "unit": "kg",
        "price": 45.85,
        "unit": "$/kg",
    },
    "OriginalGlazedDonut" : {
        "weight": 500,
        "unit": "kg",
        "price": 45.23,
        "unit": "$/kg",
    },
        "OriginalMapleDonut" : {
        "weight": 500,
        "unit": "kg",
        "price": 64.11,
        "unit": "$/kg",
    },
        "OriginalSugarDonut" : {
        "weight": 500,
        "unit": "kg",
        "price": 34.1,
        "unit": "$/kg",
    },
}

Explanantion:-

"BatterName + ToppingName" : { "weight": 500(batter weight), "unit": "kg"(hard coded), "price": 34.1(batter price + topping price), "unit": "$/kg"(hard coded, }

For example if Batter Name is "Chocolate", then there will be 6 toppings for Chocolate batter and so on for each batter. So total batter number is 4 and topping is 8 , I want 32 items in the final output


Solution

  • You basically need a cross join on toppings and batters. You can use join from dw::core::Arrays to do that. It accepts the 2 arrays as input along with two joining criteria (which are inline functions). For that you can just pass a function that always returns true (or any other static value but it should be same in both criteria functions) so the function will merge every item with every item, and you will get all combos possible.

    I noticed that the names of the snack after combining is not very straight forward, so I crated a separated function for that.

    %dw 2.0
    import join from dw::core::Arrays
    import capitalize from dw::core::Strings
    output application/json
    
    fun getComboName(batterName, toppingName, snackType) = 
        capitalize(batterName) 
        ++ (if(lower(batterName) != "original")("Flavoured") else "")
        ++ (if(lower(toppingName) != "none") capitalize((toppingName splitBy " ")[-1]) else "")
        ++ capitalize(snackType) 
    ---
    join(
        payload.batters.batter,
        payload.topping,
        (a) -> true,
        (a) -> true
    )
    reduce ((combo, acc={"type": payload."type"}) -> {
        (acc),
        (getComboName(combo.l."type", combo.r."type", payload."type")): {
            weight: combo.l.weight,
            unit: "kg",
            price: (combo.l.price default 0) + (combo.r.price default 0),
            unit: "\$/kg"
        }
    })