Search code examples
javakotlinapache-beamavro

How to read/update values in a nested Avro Generic Record?


I'm trying to access a nested field in Avro Generic Record using Apache Beam Pardo.

I can get into the first level, but I can't figure out how to access fields that are even further.

For if you consider the Generic Record value like this:

{
    "eventTargetType": "GROUP",
    "id": "1234",
    "group":
    {
        "details":
        {
           
            "triggers":
            [],
            "attributes":
            []
        },
        "groupRole":
        {
            "algorithmResults":
            []
        },
        "activeTests":
        []
    }
}

I'm able to get to the group level by doing this:

@ProcessElement
fun processElement(input: ProcessContext, output: OutputReceiver<GenericRecord>) {
    input.element().getAsGenericRecord("event").get("group")
}

and this returns value which is a data type of (org.apache.avro.generic.GenericData$Record):

{
    "event": "RENDER",
    "details":
    {
        "ow": null,
        "ty": null,
        "na": null,
        "attributes":[],
    },
    "loc": null,
    "pos": null
}

Now I want to get the field attributes which is inside details. I can't do another get() since it doesn't allow. Any ideas on how can I approach this?


Solution

  • I was able to achieve this by three approaches.

    1st Approach is to convert the Avro Generic Record to JsonObject and then access the nested fields

    val jsonObj = JSONObject(newElement.getAsGenericRecord("event")?.get("group").toString())
    val bannerJsonObject = jsonObj.getJSONObject("details").getJSONObject("nested")
    if (bannerJsonObject.get("abc").toString() == "null"){
        bannerJsonObject.put("abc","dummy")
    }
    

    2nd Approach was to cast the values into Generic Record:

    val dataNestedObjGroup = newElement.getAsGenericRecord("event")?.get("group") as GenericRecord
    val dataNestedObjDetails = dataNestedObjGroup.getAsGenericRecord("details")?.get("nested") as GenericRecord
    
    if (dataNestedObjDetails.get("abc") == null){
        dataNestedObjDetails.put("abc","dummy")
    }
    

    3rd approach was to navigate through the nested level:

    val event = newElement.getAsGenericRecord("event")
    val group = event?.getAsGenericRecord("group")
    val details = group?.getAsGenericRecord("details")
    val nested = details?.getAsGenericRecord("nested")
    
    if (nested?.get("abc") == null){
        nested?.put("abc","dummy")
    }