Search code examples
javascriptarraysobjectlodashjavascript-objects

Create object paths from a deeply nested object (Schema)


I have an avro schema, which is a deeply nested object with the same (sub)-structure. It looks like this:

{
  "type": "record",
  "namespace": "company.car.v1",
  "name": "CarV1",
  "fields": [
    {
      "name": "plateNumber",
      "type": "string"
    },
    {
      "name": "ownerId",
      "type": "string",
      "keepThisField": "true"
    },
    {
      "name" : "details",
      "keepThisField": "true"
      "type" : {
            "type" : "record",
            "name" : "DetailsV1",
            "fields" : [
              {
                "name": "engine",
                "type": {
                  "type": "record",
                  "name": "EngineV1",
                  "fields": [
                    {
                      "name": "size",
                      "type": "int",
                      "default": 0,
                      "keepThisField": "true"
                    },
                    {
                      "name": "valvesCount",
                      "type": "int",
                      "default": 0
                    }
                  ]
                }
              },
              {
                "name" : "color", 
                "type" : "string", 
                "default" : "NONE"
              },
              {
                "name" : "rimSize",
                "type" : "int", 
                "default" : "NONE"
              }
             ]},
             "default" : {}
   },
    {
      "name": "isBrandNew",
      "type": "boolean"
    }
  ]
}

I want to be able to generally get all the object paths of this object (Schema) in JavaScript. So having something like a extractPaths(avroSchema) which for the example above would return:

[
   "plateNumber",
   "ownerId",
   "details.engine.size",
   "details.engine.valvesCount",
   "details.color",
   "details.rimSize",
   "isBrandNew"
]

The order of the strings does not matter obviously. Anyone has an idea how this can be achieved in JavaScript?


Solution

  • Use a recursive generator function for generate path string.

    var schema = { "type": "record", "namespace": "company.car.v1", "name": "CarV1", "fields": [{ "name": "plateNumber", "type": "string" }, { "name": "ownerId", "type": "string", "keepThisField": "true" }, { "name": "details", "keepThisField": "true", "type": { "type": "record", "name": "DetailsV1", "fields": [{ "name": "engine", "type": { "type": "record", "name": "EngineV1", "fields": [{ "name": "size", "type": "int", "default": 0, "keepThisField": "true" }, { "name": "valvesCount", "type": "int", "default": 0 }] } }, { "name": "color", "type": "string", "default": "NONE" }, { "name": "rimSize", "type": "int", "default": "NONE" }] }, "default": {} }, { "name": "isBrandNew", "type": "boolean" }] }
    
    function* extractPaths(schema, value) {
        for (const { name, type } of schema.fields) {
            let path = value ? `${value}.${name}` : name
            if (typeof type == "object")
                yield* extractPaths(type, path);
            else
                yield path
        }
    }
    console.log([...extractPaths(schema)]);