2

How can I sort this array? I am trying to group an array of objects from a parentId that each element of the array brings, there can always be an indeterminate number of levels, the result I expect is the one I have in the output.

Input:

[
  {
    "_id": "123",
    "name": "ABC",
    "parentID": ""
  },
  {
    "_id": "645",
    "name": "ABC 2",
    "parentID": "123"
  },
  {
    "_id": "65",
    "name": "ABC 3",
    "parentID": ""
  }
]

Output:

[
  {
    "_id": "123",
    "name": "ABC",
    "parentID": "",
    "children": [
      {
        "_id": "645",
        "name": "ABC 2",
        "parentID": "123"
      },
    ]
  },
  {
    "_id": "65",
    "name": "ABC 3",
    "parentID": ""
  }
]

Thanks for help

2
  • Removed references to Typescript and React since this is a basic Javascript question Commented Sep 15, 2022 at 5:43
  • Can you look into this as well stackoverflow.com/questions/18017869/…. Only the tree creation. For sorting you will still need some work done. Commented Sep 15, 2022 at 5:54

3 Answers 3

1

This should work even for nested children:

const input = [{
        "_id": "123",
        "name": "ABC",
        "parentID": ""
    },
    {
        "_id": "645",
        "name": "ABC 2",
        "parentID": "123"
    },
    {
        "_id": "65",
        "name": "ABC 3",
        "parentID": "645"
    }
]

function map(data) {
    const childMap = data.reduce((map, child) => {
        return {
            ...map,
            [child._id]: {
                ...child
            }
        };
    }, {});

    const root = [];

    Object.values(childMap).forEach((child) => {
        if (child.parentID) {
            if (childMap[child.parentID]) {
                const parent = childMap[child.parentID];
                if (!parent.children) {
                    parent.children = [];
                }

                parent.children.push(child)
            }
        } else {
            root.push(child);
        }
    })

    return root;
}

console.log(map(input));

Sign up to request clarification or add additional context in comments.

Comments

1

You can try this approach with reduce and filter

const input = [{
    "_id": "123",
    "name": "ABC",
    "parentID": ""
  },
  {
    "_id": "645",
    "name": "ABC 2",
    "parentID": "123"
  },
  {
    "_id": "65",
    "name": "ABC 3",
    "parentID": ""
  }
]

function mapChildren(data) {
  //set the output with all results having no parent ids by default
  let output = data.filter(x => !x.parentId)

  //add children to existing results
  output = data.reduce((result, current) => {
    const {
      parentID
    } = current

    if (!parentID) {
      return result
    }

    const existingRecord = result.find(x => x._id === parentID)

    if (existingRecord) {
      if(!existingRecord.children) {
        existingRecord.children = []
      }
    
      existingRecord.children.push({...current})
    }

    return result

  }, output)

  return output
}

console.log(mapChildren(input))

Comments

1

Stuff like that is a job for database engines. You are not supposed to do this on Controller's side. The Model is supposed to send you data the way you want. Just ask the backend guy to make a route with the data sent like that, or just add some if statements to your data parsing method to do stuff differently based on whether an object has parentId or not.

But if you really want to do it on frontend side, you can do it like this:

const data = [
    {
        _id: '123',
        name: 'ABC',
        parentID: '',
    },
    {
        _id: '645',
        name: 'ABC 2',
        parentID: '123',
    },
    {
        _id: '65',
        name: 'ABC 3',
        parentID: '',
    },
];

const restructureData = (data) => {
    const children = data.filter((object) => object.parentID);
    const parents = data.filter((object) => !object.parentID);

    for (let i = 0; i < children.length; i++) {
        let parentIndex = parents
            .map((object) => object._id)
            .indexOf(children[i].parentID);
        if (!parents[parentIndex].children) {
            parents[parentIndex].children = [];
        }
        parents[parentIndex].children.push(children[i]);
    }
    return parents;
};

console.log(restructureData(data));

This will not work for nested children though.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.