본문 바로가기

개발/JavaScript

[Javascript] plain DB 데이터로 Tree 쉽게 만들기

Tree를 만드려면 염두해야할 두가지

1. DB 데이터를 어떻게 추출하여 트리를 만들 수 있는 JSON 형태로 만들 것인가
2. 만든 JSON을 어떻게 <ul><li>태그로 추출할 것인가

 

만들 TREE 구조는 이러하다.

 

이런 트리를 만드려면 다음과 같이 각각의 노드의 Id와 parentId가 필수적으로 필요하다. 

const data = [
    { id: 56, parentId: 62 },
    { id: 81, parentId: 80 },
    { id: 74, parentId: null },
    { id: 76, parentId: 80 },
    { id: 63, parentId: 62 },
    { id: 80, parentId: 86 },
    { id: 87, parentId: 86 },
    { id: 62, parentId: 74 },
    { id: 86, parentId: 74 },
];

 

DB에서 추출한 데이터는 이렇게 매핑할 수 있다. 이 데이터를 가지고 트리로 만들어보겠다.


1. plain DB 데이터를 JSON으로 만들기

객체 참조를 이용하여 만들것이다. 해당 방법은 시간복잡도가 O(N)이기도 하고 무엇보다 간단하다.

 

 

 

86, 62는 74의 자식노드이고, 36은 62의 자식 노드이다. 우리가 만들 JSON 형태는 이런 형태이다.

 

{
    "id": 74,
    "parentId": "ROOT",
    "children": [
        {
            "id": 86,
            "parentId": 74,
            "children": []
        },
        {
            "id": 62,
            "parentId": 74,
            "children": [
                {
                    "id": 63,
                    "parentId": 62
                }
            ]
        }
    ]
}

 

부모 노드에 자식 노드가 붙어있는 계층을 이루는 구조로 만들것이다.

아래는 객체를 참조하는 원리를 그림으로 나타냈다.

 

isMapping이라는 함수는 부모가 어느 인덱스에 있는지 알려주는 객체이다. (74는 0번째 인덱스에 있고 86은 1번쨰 인덱스에 있다) 이것을 사용하여 해당 노드의 부모가 어디에 존재하는지 알아내어 부모노드의 children으로 해당 노드를 append 할것이다.

 

코드

const data = [
    { id: 56, parentId: 62 },
    { id: 81, parentId: 80 },
    { id: 74, parentId: null },
    { id: 76, parentId: 80 },
    { id: 63, parentId: 62 },
    { id: 80, parentId: 86 },
    { id: 87, parentId: 86 },
    { id: 62, parentId: 74 },
    { id: 86, parentId: 74 },
];

const idMapping = data.reduce((acc, el, i) => {
    acc[el.id] = i;
    return acc;
}, {});


window.onload = () =>{        
  console.log(idMapping);
}

 

결과값

{"56":0,"62":7,"63":4,"74":2,"76":3,"80":5,"81":1,"86":8,"87":6}

 

노드들이 인덱스와 잘 맵핑되었다.

 

이제 JSON을 그려보자.

let root;
const makeTree = data.forEach((el) => {
    // 루트인 경우
    if (el.parentId === null) {
        el.parentId = "ROOT";
        root = el;
        return;
    }
    // idMapping으로 현재 el의 parrentId의 위치 찾기 
    const parentEl = data[idMapping[el.parentId]];

    // 현재 el을 parentEl의 children으로 넣는다.
    parentEl.children = [...(parentEl.children || []), el];
});

window.onload = () =>{        
    const data = [];
    data.push(root);
}

 

결과값

[
  {
    "id": 74,
    "parentId": "ROOT",
    "children": [
      {
        "id": 62,
        "parentId": 74,
        "children": [
          {
            "id": 56,
            "parentId": 62
          },
          {
            "id": 63,
            "parentId": 62
          }
        ]
      },
      {
        "id": 86,
        "parentId": 74,
        "children": [
          {
            "id": 80,
            "parentId": 86,
            "children": [
              {
                "id": 81,
                "parentId": 80
              },
              {
                "id": 76,
                "parentId": 80
              }
            ]
          },
          {
            "id": 87,
            "parentId": 86
          }
        ]
      }
    ]
  }
]

 


2. 만든 JSON을 <ul><li>태그로 추출하기

재귀를 이용하여 children이 있다면 함수를 지속적으로 호출할 것이다.

 

let node = ``;
const $myDiv = document.querySelector("#myDiv");

const drawTree = (data) => {
    for (let i in data) {
        node += `<li class="${data[i].parentId}">${data[i].id}`
        if (data[i].children) {
            node += `<ul>`
            drawTree(data[i].children) // 재귀
            node += `</ul>`
        }
        node += `</li>`;
    }
    $myDiv.innerHTML = node;
}

window.onload = () =>{        
    const data = [];
    data.push(root);

    console.log('root : ' + JSON.stringify(data));
    drawTree(data);   
}

 

결과화면

 

https://github.com/datoybi/blog-posting/tree/main/tree

 

GitHub - datoybi/blog-posting: 블로그 포스팅 코드

블로그 포스팅 코드. Contribute to datoybi/blog-posting development by creating an account on GitHub.

github.com


Reference

https://typeofnan.dev/an-easy-way-to-build-a-tree-with-object-references/