dataweavemulesoftanypoint-studio

Dataweaving for complex object array


  {
    "customer": [
        {
            "account":{
                "number": 12345,
                "serno": 4000,
                "card": {
                    "id": "a",
                    "number": "a***"
                }
            }
        },
         {
             "account":[
                {
                "number": 33333,
                "serno": 1000,
                "card": {
                        "id": "a",
                        "number": "a***"
                    }
                },
                {
                "number": 22222,
                "serno": 2000,
                "card": [
                    {
                        "id": "a",
                        "number": "b***"
                    },
                    {
                        "id": "a",
                        "number": "c***"
                    },
                    {
                        "id": "a",
                        "number": "d***"
                    }
                    ]
                }
            ]
        }
    ]
}

Scripts

%dw 2.0
    output application/json
    var itemsArr = flatten(payload.customer map ((item) -> item.account.number)) 
    var reducedItems = itemsArr reduce ((item, acc) -> item ++ "," ++ acc)
    var foundItem = (flatten(payload.customer.account) filter((item) -> item.number == 22222)) 
    var obValues = [
    {
        "number" : 22222,
        "val": 113
    },
       {
        "number" : 33333,
        "val": 20
    },
       {
        "number" : 12345,
        "val": 30
    },
    ]
    ---
    flatten(payload.customer.account) map ((item) ->
      obValues map ((ob) ->
            if(item.number == ob.number)
                item update {
                    case .serno -> 54435325345
                } else 0)
            
        
    )

I tried the above without success, it is very close to how I need the data to be however I ultimately want to update the "serno" property on each "account" object from the payload if the "account"."number" is found to be in the obValues array. The "serno" property should be the "val" from the related obValue object that matches the "ob"."number". Any help with pointing me in the right direction will be appreciated. Expected outcome should be as below

  {
  "customer": [
    {
      "account": {
        "number": 12345,
        "serno": 30,
        "card": {
          "id": "a",
          "number": "a***"
        }
      }
    },
    {
      "account": [
        {
          "number": 33333,
          "serno": 20,
          "card": {
            "id": "a",
            "number": "a***"
          }
        },
        {
          "number": 22222,
          "serno": 113,
          "card": [
            {
              "id": "a",
              "number": "b***"
            },
            {
              "id": "a",
              "number": "c***"
            },
            {
              "id": "a",
              "number": "d***"
            }
          ]
        }
      ]
    }
  ]
}

Solution

  • It is important to first understand exactly what is the output that you are trying to achieve and have examples to verify it is correct. Once you can put it in words, you can translate that into DataWeave expressions. Also you should be familiar with the language to use the correct features. The script should communicate the intention of what you are trying to do for it to be clear to the reader.

    The expected output was not fully clear in the question. From my understanding I started updating the values in the customer array. For that you can use the update operator which simplifies modifying only the keys that we are interested on. Then you need to update each account, however the account could be a single object or an array, so we need to decide what to do in each case. I used pattern matching for the decision. To avoid making the expression overly complex we can encapsulate parts of it in functions so it is more readable. Finally a function updates the serno value if it finds a matching number in obValues. In the previous match if it is a single object I call the update function, if it an array I call it for every item.

    My script:

    output application/json 
    
    var obValues = [ { "number" : 22222, "val": 113 }, { "number" : 33333, "val": 20 }, { "number" : 12345, "val": 30 }, ] 
    
    fun accountInOb(n)=obValues dw::core::Arrays::firstWith(((ob) -> ob.number == n))
    
    fun updateSingleAccount(a)=
        a update {
            case .serno -> accountInOb(a.number).val default $
        }
    
    fun updateAccount(a)=
        a update {
            case .account -> $ match {
                case is Array -> $ map (updateSingleAccount($))
                case is Object -> updateSingleAccount($)
            }
        }
    --- 
    payload update {
        case c at .customer -> c map (updateAccount($))
    }
    

    Output:

    {
      "customer": [
        {
          "account": {
            "number": 12345,
            "serno": 30,
            "card": {
              "id": "a",
              "number": "a***"
            }
          }
        },
        {
          "account": [
            {
              "number": 33333,
              "serno": 20,
              "card": {
                "id": "a",
                "number": "a***"
              }
            },
            {
              "number": 22222,
              "serno": 113,
              "card": [
                {
                  "id": "a",
                  "number": "b***"
                },
                {
                  "id": "a",
                  "number": "c***"
                },
                {
                  "id": "a",
                  "number": "d***"
                }
              ]
            }
          ]
        }
      ]
    }