菜鸟笔记:node.js+mysql中将JSON数据构建为树(递归制作树状菜单数据接口)

初学Web端开发,今天是第一次将所学做随笔记录,肯定存在多处欠妥,望大家海涵;若有不足,望大家批评指正。

进实验室后分配到的第一个项目,需要制作一个不确定层级树形菜单的数据接口,对于从来没实战编过程的我,存在太多需要学习的地方。

开发环境:Atom;

语言:javascript;

其他:nodejs;mysql;express;

输入:通过sql语句转换出的一个个JSON对象,如:其中id为唯一编号,parent为其父级的id号。

 1 [
 2     {
 3         "id": 1,
 4         "name": "111",
 5         "parent": null,
 6         "icon": "555,,"
 7     },
 8     {
 9         "id": 2,
10         "name": "极地测试菜单2",
11         "parent": 1,
12         "icon": "/img/002.png"
13     },
14     {
15         "id": 4,
16         "name": "555",
17         "parent": 2,
18         "icon": "88"
19     },
20     {
21         "id": 5,
22         "name": "ddd",
23         "parent": 2,
24         "icon": "555.png"
25     },
26     {
27         "id": 6,
28         "name": "666",
29         "parent": 4,
30         "icon": null
31     },
32     {
33         "id": 7,
34         "name": "777",
35         "parent": 5,
36         "icon": null
37     },
38     {
39         "id": 9,
40         "name": "8888",
41         "parent": 1,
42         "icon": null
43     },
44     {
45         "id": 10,
46         "name": "9999",
47         "parent": 9,
48         "icon": null
49     },
50     {
51         "id": 11,
52         "name": "10000",
53         "parent": 1,
54         "icon": null
55     }
56 ]

输出:树状JSON结构

 1 {
 2     "id": 1,
 3     "name": "111",
 4     "parent": null,
 5     "icon": "555,,",
 6     "sub": [
 7         {
 8             "id": 2,
 9             "name": "极地测试菜单2",
10             "parent": 1,
11             "icon": "/img/002.png",
12             "sub": [
13                 {
14                     "id": 4,
15                     "name": "555",
16                     "parent": 2,
17                     "icon": "88",
18                     "sub": [
19                         {
20                             "id": 6,
21                             "name": "666",
22                             "parent": 4,
23                             "icon": null,
24                             "sub": []
25                         }
26                     ]
27                 },
28                 {
29                     "id": 5,
30                     "name": "ddd",
31                     "parent": 2,
32                     "icon": "555.png",
33                     "sub": [
34                         {
35                             "id": 7,
36                             "name": "777",
37                             "parent": 5,
38                             "icon": null,
39                             "sub": []
40                         }
41                     ]
42                 }
43             ]
44         },
45         {
46             "id": 9,
47             "name": "8888",
48             "parent": 1,
49             "icon": null,
50             "sub": [
51                 {
52                     "id": 10,
53                     "name": "9999",
54                     "parent": 9,
55                     "icon": null,
56                     "sub": []
57                 }
58             ]
59         },
60         {
61             "id": 11,
62             "name": "10000",
63             "parent": 1,
64             "icon": null,
65             "sub": []
66         }
67     ]
68 }

即将从mysql中取出的一条一条JSON数据,按照parent所指向的id号,转变为树桩JSON结构,供AngularJS框架自动生成树桩菜单。

示例图:

 

变量声明:allMenu为初始输入的JSON数据格式,即包含一条一条JSON对象的数组。

       对象的sub属性放置当前对象的所有子节点数组。

思想:利用递归/循环进行树的层级遍历。

   比如输入一个根节点对象,首先应对allMenu遍历寻找parent为根节点id的所有对象(方法命名为findItemChild),并将其置入一个临时数组childlist中。然后对该childlist进行遍历,对其中每一个对象利用递归方法,返回该对象的childList并添加进当前对象的sub中,往复递归。举个例子:即当方法输入id=1的对象后,findItemChild方法通过遍历会返回一个数组[{id:2,parent:1,...},{id:9,parent:1,...},{id:11,parent:1,...}],之后对该数组进行遍历,即将id=2的对象递归输入方法,并将获取的childlist遍历继续递归。。。。即树的层级遍历。

算法:

  输入:JSON对象item

  function getAllChild(res){

  ①获取所有父级为根节点id的子对象数组childlist

  ②若childlist为空,则返回[]

  ③若childlist不为空,遍历childlist,并对每一个childlist[k]递归调用getAllChild(childlist[k])赋予childlist[k].sub

  ④将childlist输入res.sub

  ⑤返回childlist

  }

      输出:以对象item为根节点的树状JSON对象

代码:

 1 router.get('/:id', function(req, res, next) {
 2 
 3 
 4   pool.getConnection(function(err, connection) {
 5     if (err) return next(err);
 6 
 7       connection.query('SELECT * from menuitems ', function(err, rows, fields) {
 8         if (err) throw err;
 9         //get all data
10         var result = [];//存放起始对象
11         var allMenu = rows;//获取sql出的全部json对象
12         for(i=0;i<allMenu.length;i++){
13           if(allMenu[i].id == req.params.id){
14             result.push(allMenu[i]) ;//根据id号获取根对象
15             break;
16           }
17         }
18        //judege result exist or not
19         if(result.length==0){
20 
21            return res.json('Failed! id is not exist!');
22 
23         }else{
24 
25           result.sub=[];
26           result.sub=getAllChild(result);//调用
27           res.json(result[0]);
28 
29         }
30         //find some item all child
31         function findItemChild(item){
32           var arrayList=[];
33           for(var i in allMenu){
34             if(allMenu[i].parent == item.id){
35               arrayList.push(allMenu[i]);
36             }
37           }
38           return arrayList;
39         }
40         //get all child
41         function getAllChild(array){
42           var childList=findItemChild(array[0]);
43           if(childList == null){
44             return [];
45           }
46           else{
47             for(var j in childList){
48               childList[j].sub=[];
49               childList[j].sub=getAllChild([childList[j]]);
50             }
51             array[0].sub=childList;
52           }
53           return childList;
54 
55         }
56       });
57   });
58 });

 

代码执行过程:

  getAllChild([id=1])

  childlist=[{id:2,parent:1,...},{id:9,parent:1,...},{id:11,parent:1,...}];

      for(id=2          id=9           id=11) 

           ↓ 

  childlist[id=2].sub=?

                                  ↓

                                 getAllChild([id=2]);

                childlist=[{id:4,parent:2,...},{id:5,parent:2,...}];

               for(id=4       id=5)

                                            ↓ 

                                    childlist[id=4].sub=?

                                                                    ↓ 

                               getAllChild([id=4]);

                            childlist=[{id:6,parent:4,...}];

                                                                  for(id=6)

                                                                                          ↓ 

                                                                                  childlist[id=6].sub=?

                                                                                                                  ↓ 

                                                                                                        getAllChild([id=6]),return [];//到底,依次往上返回,将childlist逐步扩充,直到最终返回allchild;

 

扩充:返回所有树状菜单,即寻找所有JSON数据构成的森林。思想是通过给森林构造一个根节点转换为树,再利用上述方法实现。

  

 1 router.get('/', function(req, res, next) {
 2 
 3   pool.getConnection(function(err, connection) {
 4     if (err) return next(err);
 5     connection.query('SELECT * from menuitems ', function(err, rows, fields) {
 6       if (err) throw err;
 7       //get all data
 8       //create a id= null root for forest
 9       var temp_parent={"id":null,"sub":[]};//新建id为null的对象做为森林的根
10       var result=[];
11       var allMenu = rows;
12 
13        result.push(temp_parent) ;
14 
15       var output = getAllChild(result);
16       if(output.length==0){
17         //if our database do note have any data
18         return res.json('Failed! do not have any data!');
19       }else {
20         res.json(output);
21       }
22 
23       //find some item all child   //方便阅读依然放上此方法
24       function findItemChild(item){
25         var arrayList=[];
26         for(var i in allMenu){
27           if(allMenu[i].parent == item.id){
28             arrayList.push(allMenu[i]);
29           }
30         }
31         return arrayList;
32       }
33       //get all child          //方便阅读依然放上此方法
34       function getAllChild(array){   
35         var childList=findItemChild(array[0]);
36         if(childList == null){
37           return [];
38         }
39         else{
40           for(var j in childList){
41             childList[j].sub=[];
42             childList[j].sub=getAllChild([childList[j]]);
43           }
44           array[0].sub=childList;
45         }
46         return childList;
47 
48       }
49 
50       });
51 
52 });
53 });

总结:通过javascript语言利用NodeJS结合mysql可以实现从后台拿到JSON数据后,将数据构造成树状结构的形式供前端使用。这种Javascript全栈开发方式还有很多需要学习。未来的路还很长,加油!

递归的写法需要时常琢磨寻找好的返回方式,在本文的思想下,递归方法的输入与返回的形式应统一,防止程序陷入死循环或不可执行,实在无法下手时应该通过画流程图的形式判断递归的有效性。递归在树层级比较深时肯定会耗费大量计算时间,因此之后通过学习寻找更好的解决方法。

tips:由于本人菜鸟一枚,所述拙见仅供自己学习总结,第一次写博客~若对您造成错误影响请批评指正。

 

  

 

posted @ 2015-11-03 22:49  EasonXu  阅读(2675)  评论(0编辑  收藏  举报