菜鸟笔记: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中的模块,平时练习就接触到那么几个,其他的 ...
随机推荐
- POJ1144(割点)
Network Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 12551 Accepted: 5771 Descript ...
- 从0到1学习node之简易的网络爬虫
本文地址: http://www.xiabingbao.com/node/2017/01/19/node-spider.html 我们这节的目标是学习完本节课程后,能进行网页简单的分析与抓取,对抓取到 ...
- 制作一个功能丰富的Android天气App
简易天气是一个基于和风天气数据采用MD设计的Android天气App.目前的版本采用传统的MVC模式构建.通过丰富多彩的页面为用户提供日常所需的天气资讯. 项目说明 项目放在github上面 地址是: ...
- Java多线程基础——Lock类
之前已经说道,JVM提供了synchronized关键字来实现对变量的同步访问以及用wait和notify来实现线程间通信.在jdk1.5以后,JAVA提供了Lock类来实现和synchronized ...
- look look C#7
vs2017也rc好几个版本了,本想跟进看看c#7加入了什么内容,去搜索c#7,确实找到了不少文章,无奈很多特性ide根本不让编译啊...所以今天主要列出已经确定了的c#7特性(一般来说rc后也不会加 ...
- NSMutableAttributedString
开发过程中,经常会遇到动态计算行高的问题, - (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)op ...
- LINQ查询表达式基础
LINQ,语言集成查询(Language Integrated Query)是一组用C#和Visual Basic语言的扩展. 对于编写查询的开发人员来说,LINQ 最明显的"语言集成&qu ...
- 一个技术汪的开源梦 —— 微信开发工具包(WeixinSDK)
由于春节的关系 WeixinSDK 这个开源项目的进展比预期推迟了大约一个月的时间,值得高兴的是到目前为止该项目的重要模块已经开发完毕. - 关于项目 该项目的背景是现在微信公众号.微信服务号乃至微 ...
- Java设计和实现方法
方法签名 方法名是驼峰命名 方法名最好能说明该方法主要做什么 方法参数的名字最好能说明该参数的意义 方法参数个数最好低于6个 例如: public void setTitleVisible(int l ...
- wordPress查看站点时,显示文件目录
1.在wordpress的代码目录中增加.htaccess文件. 2.在.htaccess文件中加入如下内容: DirectoryIndex index.php index.html# BEGIN W ...
