javascriptjsonobjectorganizational-chart

Javascript build a tree from a string with object.create()


I'd like to create a tree of services from a string which are properties of people. I manage to do it, but the code is quite ugly, and it's a king of practice for me for the trick is i'd like to make it with "class" of objects using "Object.create()" where the class would look like this :

let service = {
        serviceFather: "",
        serviceChildren: [],
        people: [],
        }
    }; 

A sample of input is :

[
  {
    "name": "John Doe",
    "service": "EE",
  },
  {
    "name": "Jane Doe",
    "service": "EE.EA",
  },
  {
    "name": "Jack Smith",
    "service": "EE.EA.EB",
  },
  {
    "name": "Jill Smith",
    "service": "EE.EA.EC"
  },
  {
    "name": "Jake Smith",
    "serviceLevel": "EE.EA.EC"
  }
]

The expected output would be :

[
{
    "name": "EE",
    "serviceFather": "root",
    "people": [
    {
        "name": "John Doe"
    }],
    "serviceChildren": [
    {
        "name": "EA",
        "serviceFather": "EE",
        "people": [
        {
            "name": "Jane Doe"
        }],
        "serviceChildren": [
        {
            "name": "EB",
            "serviceFather": "EA",
            "people": [
            {
                "name": "Jack Smith"
            }],
            "sousService": ""
        },
        {
            "name": "EC",
            "serviceFather": "EA",
            "people": [
            {
                "name": "Jill Smith"
            },
            {
                "name": "Jake Smith"
            }],
            "sousService": ""
        }]
    }]
}]

Solution

  • You could use split on service property and then forEach loop and reduce to iterate nested tree and add to array.

    const data = [{ "name": "John Doe", "service": "EE" }, { "name": "Jane Doe", "service": "EE.EA" }, { "name": "Jack Smith", "service": "EE.EA.EB" },
      { "name": "Jill Smith", "service": "EE.EA.EC" }, { "name": "Jake Smith", "service": "EE.EA.EC" }
    ]
    
    let service = {
      serviceFather: "",
      serviceChildren: [],
      people: [],
    };
    
    function create(data) {
      const res = []
      data.forEach(obj => {
        obj.service.split('.').reduce((r, e, i, a) => {
          const match = r.find(({ name }) => name == e);
          if(!match) {
            const o = Object.create(service);
            o.name = e;
            o.serviceFather = (i == 0 ? 'root' : a[i - 1])
            o.people = [{ name: obj.name }]
            o.serviceChildren = [];
            r.push(o)
            return r;
          } else {
            if(!a[i + 1]) match.people.push({ name: obj.name })
            return match.serviceChildren
          }
        }, res)
      })
      return res;
    }
    
    const result = create(data)
    console.log(result)