菜鸟笔记:node.js+mysql中将JSON数据构建为树(递归制作树状菜单数据接口)
初学Web端开发,今天是第一次将所学做随笔记录,肯定存在多处欠妥,望大家海涵;若有不足,望大家批评指正。
进实验室后分配到的第一个项目,需要制作一个不确定层级树形菜单的数据接口,对于从来没实战编过程的我,存在太多需要学习的地方。
开发环境:Atom;
语言:javascript;
其他:nodejs;mysql;express;
输入:通过sql语句转换出的一个个JSON对象,如:其中id为唯一编号,parent为其父级的id号。
[
{
"id": 1,
"name": "111",
"parent": null,
"icon": "555,,"
},
{
"id": 2,
"name": "极地测试菜单2",
"parent": 1,
"icon": "/img/002.png"
},
{
"id": 4,
"name": "555",
"parent": 2,
"icon": "88"
},
{
"id": 5,
"name": "ddd",
"parent": 2,
"icon": "555.png"
},
{
"id": 6,
"name": "666",
"parent": 4,
"icon": null
},
{
"id": 7,
"name": "777",
"parent": 5,
"icon": null
},
{
"id": 9,
"name": "8888",
"parent": 1,
"icon": null
},
{
"id": 10,
"name": "9999",
"parent": 9,
"icon": null
},
{
"id": 11,
"name": "10000",
"parent": 1,
"icon": null
}
]
输出:树状JSON结构
{
"id": 1,
"name": "111",
"parent": null,
"icon": "555,,",
"sub": [
{
"id": 2,
"name": "极地测试菜单2",
"parent": 1,
"icon": "/img/002.png",
"sub": [
{
"id": 4,
"name": "555",
"parent": 2,
"icon": "88",
"sub": [
{
"id": 6,
"name": "666",
"parent": 4,
"icon": null,
"sub": []
}
]
},
{
"id": 5,
"name": "ddd",
"parent": 2,
"icon": "555.png",
"sub": [
{
"id": 7,
"name": "777",
"parent": 5,
"icon": null,
"sub": []
}
]
}
]
},
{
"id": 9,
"name": "8888",
"parent": 1,
"icon": null,
"sub": [
{
"id": 10,
"name": "9999",
"parent": 9,
"icon": null,
"sub": []
}
]
},
{
"id": 11,
"name": "10000",
"parent": 1,
"icon": null,
"sub": []
}
]
}
即将从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对象
代码:
router.get('/:id', function(req, res, next) { pool.getConnection(function(err, connection) {
if (err) return next(err); connection.query('SELECT * from menuitems ', function(err, rows, fields) {
if (err) throw err;
//get all data
var result = [];//存放起始对象
var allMenu = rows;//获取sql出的全部json对象
for(i=0;i<allMenu.length;i++){
if(allMenu[i].id == req.params.id){
result.push(allMenu[i]) ;//根据id号获取根对象
break;
}
}
//judege result exist or not
if(result.length==0){ return res.json('Failed! id is not exist!'); }else{ result.sub=[];
result.sub=getAllChild(result);//调用
res.json(result[0]); }
//find some item all child
function findItemChild(item){
var arrayList=[];
for(var i in allMenu){
if(allMenu[i].parent == item.id){
arrayList.push(allMenu[i]);
}
}
return arrayList;
}
//get all child
function getAllChild(array){
var childList=findItemChild(array[0]);
if(childList == null){
return [];
}
else{
for(var j in childList){
childList[j].sub=[];
childList[j].sub=getAllChild([childList[j]]);
}
array[0].sub=childList;
}
return childList; }
});
});
});
代码执行过程:
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数据构成的森林。思想是通过给森林构造一个根节点转换为树,再利用上述方法实现。
router.get('/', function(req, res, next) { pool.getConnection(function(err, connection) {
if (err) return next(err);
connection.query('SELECT * from menuitems ', function(err, rows, fields) {
if (err) throw err;
//get all data
//create a id= null root for forest
var temp_parent={"id":null,"sub":[]};//新建id为null的对象做为森林的根
var result=[];
var allMenu = rows; result.push(temp_parent) ; var output = getAllChild(result);
if(output.length==0){
//if our database do note have any data
return res.json('Failed! do not have any data!');
}else {
res.json(output);
} //find some item all child //方便阅读依然放上此方法
function findItemChild(item){
var arrayList=[];
for(var i in allMenu){
if(allMenu[i].parent == item.id){
arrayList.push(allMenu[i]);
}
}
return arrayList;
}
//get all child //方便阅读依然放上此方法
function getAllChild(array){
var childList=findItemChild(array[0]);
if(childList == null){
return [];
}
else{
for(var j in childList){
childList[j].sub=[];
childList[j].sub=getAllChild([childList[j]]);
}
array[0].sub=childList;
}
return childList; } }); });
});
总结:通过javascript语言利用NodeJS结合mysql可以实现从后台拿到JSON数据后,将数据构造成树状结构的形式供前端使用。这种Javascript全栈开发方式还有很多需要学习。未来的路还很长,加油!
递归的写法需要时常琢磨寻找好的返回方式,在本文的思想下,递归方法的输入与返回的形式应统一,防止程序陷入死循环或不可执行,实在无法下手时应该通过画流程图的形式判断递归的有效性。递归在树层级比较深时肯定会耗费大量计算时间,因此之后通过学习寻找更好的解决方法。
tips:由于本人菜鸟一枚,所述拙见仅供自己学习总结,第一次写博客~若对您造成错误影响请批评指正。
菜鸟笔记:node.js+mysql中将JSON数据构建为树(递归制作树状菜单数据接口)的更多相关文章
- Node.js + MySQL 实现数据的增删改查
通过完成一个 todo 应用展示 Node.js + MySQL 增删改查的功能.这里后台使用 Koa 及其相应的一些中间件作为 server 提供服务. 初始化项目 $ mkdir node-cru ...
- 零代码第一步,做个添加数据的服务先。node.js + mysql
node.js + mysql 实现数据添加的功能.万事基于服务! 增删改查之添加数据. 优点:只需要设置一个json文件,就可以实现基本的添加功能,可以视为是零代码. 添加数据的服务实现的功能: 1 ...
- node.js+mysql环境搭建
https://www.jianshu.com/p/9b338095cbe8 node.js+mysql环境搭建 0x01 前言 随着html web技术的发展,和全栈式开发的需求,对于前端人员来讲, ...
- Node.js NPM Package.json
章节 Node.js NPM 介绍 Node.js NPM 作用 Node.js NPM 包(Package) Node.js NPM 管理包 Node.js NPM Package.json Nod ...
- Node.js实操练习(一)之Node.js+MySQL+RESTful
前言 最近学习了一下node.js相关的内容,在这里初步做个小总结,说实话关于本篇博客的相关内容,自己很久之前就已经有过学习,但是你懂的,“好记性不如烂笔筒”,学过的东西不做笔记的话,很容易就会忘记的 ...
- Ubuntu 16.04 下部署Node.js+MySQL微信小程序商城
转载于这篇文章 关于pm2看这篇文章 最近在研究小程序,申请了域名之后,再一次来配置环境,根据作者的步骤基本上完成了网站的架构,但由于环境路径等不同,配置上会有所不同,因此记录下来. 1.更新系统和安 ...
- node.js+mysql用户的注册登录验证
下面代码实现的功能是:用node.js连接mysql实现用户的注册和登录,这里主要实现的是后端的验证代码,前端显示部分没具体写出. 整个程序的流程是这样的: 1.首先建立数据库reji,数据表user ...
- Node.js学习笔记——Node.js开发Web后台服务
一.简介 Node.js 是一个基于Google Chrome V8 引擎的 JavaScript 运行环境.Node.js 使用了一个事件驱动.非阻塞式 I/O 的模型,使其轻量又高效.Node.j ...
- 笔记-Node.js中的核心API之HTTP
最近正在学习Node,在图书馆借了基本关于Node的书,同时在网上查阅资料,颇有收获,但是整体感觉对Node的理解还是停留在一个很模棱两可的状态.比如Node中的模块,平时练习就接触到那么几个,其他的 ...
随机推荐
- Android内存泄露---检测工具篇
内存使用是程序开发无法回避的一个问题.如果我们毫不在意肆意使用,总有一天会为此还账,且痛不欲生...所以应当防患于未然,把内存使用细化到平时的每一行代码中. 内存使用概念较大,本篇先讲对已有app如何 ...
- Scala入门笔记二
[TOC] 标识符 可用的字符 处理括号类字符,分隔符之外,其他所有的可打印的ASCII字符,如字母,数字,下划线和美元符号($)均可出现在Scala标识符中 插入符包括了(,) [,] {,and} ...
- 自己开发轻量级ORM(二)
上一篇简单的对轻量级ORM开发开了个头.这篇主要聊下ORM框架的设计思路. ORM本质上是对数据库操作的抽象.大体上我将其分为对数据结构的抽象和对执行方法的抽象. 我的ORM设计图: ORM框架需要完 ...
- iOS开发一些小技巧
1.隐藏多余的tableView的cell分割线 self.tableView.tableFooterView= [[UIViewalloc]init]; 2.取消系统自带的返回字样 [[UIBarB ...
- Ubuntu 14.04 64bit 系统下打开PHPadmin时出现缺少mysqli|mysql 扩展的解决方法(php5)
网上找了很多方法,都是翻来覆去的抄袭. 都在说把 /etc/php5/apache2/php.ini 下面的 ;extension=php_mysqli.dll 前面的 ; 注释符号去掉 再重启 ...
- matlab 利用while循环计算平均值和方差(第二版)
第一版中因为公式中含有:分母项:n(n-1),而程序并没有对输入数进行判定,如果仅仅输入一个或者一个都不输入,将会出现除0的情况 基于此,进行第二版改进. 代码: % 脚本文件:states.m % ...
- php上线教程----阿里云下设值二级域名并将项目上线
在工作中,我们需要在一个主机地址下分配多个域名来上线多个项目,但是怎么设置一个二级域名并且完成上线项目的,接下来我们就以阿里云为例演示整个上线流程 首先登陆你的阿里云,找到你的域名 点击解析,进入解析 ...
- 随机生成并排序 C,去同,有序数组合并排序
#include<iostream> #include<stdlib.h> #include<time.h> using namespace std; int ma ...
- noi 1.8 11图像旋转
水题不解释 其实我偷懒了 直接输出,,,,,,, 个人QQ:757394026团队QQ:466373640个人博客:www.doubleq.winc++/noi/信息学奥数博客:http://www. ...
- 【转】CXF+Spring+Eclipse简明示例
多系统(异构系统)进行交互时,一种良好的方式便是调用Web Service,本示例基于Apache组织的CXF,为了方便起见特将服务端和客户端写在同一个工程下,实际项目中是不可能的,但是客户端却依赖于 ...