Search code examples
dataweave

How can I access an object's properties in a reduce function?


I'm converting an array of objects to an object of key:value pairs, where the value is an string aggregation. My challenge is that I do not now how to access obj properties, while using reduce ( (env,obj={})

Currently I can weave the following payload:

{
"records": [{
            "MetadataComponentName": "ClassB",
            "RefMetadataComponentName": "ClassC"
        },{
            "MetadataComponentName": "ClassA",
            "RefMetadataComponentName": "ClassB"
        }
    ]
}

to

{
  "ClassB": "ClassC",
  "ClassA": "ClassB",
}

But the goal is to achieve:

{
  "ClassA": "ClassB,ClassC",
}

The script is:

%dw 2.0
output application/json
---
payload.records reduce (
    (env,obj={}) ->        
            obj ++ {
            (env.MetadataComponentName):env.RefMetadataComponentName
             }
)

And I've tested accessing obj in a conditional as follows:

%dw 2.0
output application/json
---
payload.records reduce (
    (env,obj={}) ->        
        if ((obj['MetadataComponentName']=="ClassB"))
            obj ++ {
            (env.MetadataComponentName):env.RefMetadataComponentName
             }
        else null
)

which produces a null result! Negating the conditional - if (!(obj['MetadataComponentName']=="ClassB")) obj ++ { produces the same output as without the conditional at all.

My intended logic would be to ultimately prevent deduplicating keys:

if (!(obj['MetadataComponentName']==env.MetadataComponentName))
            obj ++ {
            (env.MetadataComponentName):env.RefMetadataComponentName
             }
        else 
            (env.MetadataComponentName): obj['MetadataComponentName'] + env.RefMetadataComponentName

Questions:

  • Is it possible to access an object's property's in the reduce function?
  • Is obj['MetadataComponentName'] the correct syntax to retrieve a value?
  • Is the correct solution to define a function that performs this key dedupe?

Thoughts and opinions much appreciated.


Solution

  • Note that reduce works on arrays, and the state it keeps is just an accumulator and the current element. I don't understand why do see a limitation on accessing the properties of the object. Your scripts access the properties correctly in different ways.

    It looks just that you are trying to use reduce() in a way that is not well matched to it. I recommend to keep it simple and use reduce to accumulate the values you need in an easy way to operate, then transform that in the expected result.

    Example:

    %dw 2.0
    output application/json
    var result=payload.records 
        reduce (
            (env,obj={lastKey: null, names:[]}) ->        
                {
                lastKey: env.MetadataComponentName,
                names: ([env.RefMetadataComponentName] ++ obj.names)  
                }
        )
    ---
    { (result.lastKey): result.names joinBy ","}
    

    Output:

    {
      "ClassA": "ClassB,ClassC"
    }
    

    The result is what was asked. I'm not sure if the algorithm I used is the one you want because the logic that you were trying to achieve was not clarified in the question.

    Using obj.MetadataComponentName and obj['MetadataComponentName'] give the same result. The second form is the dynamic selector one usually used with the index being expressions or variables rather than literal strings.