花了4天时间撸了一个问卷调查系统,算是入门nodejs后端开发。
github传送门:https://github.com/flute/survey
技术
- 后端:nodejs+express+mysql
- 前端:material design
install
npm install
- 配置数据库
conf/db.js
,导入sql文件 mysql.sql
node app.js
功能
- 登陆验证
- 问题类型包括 单选、多选及问答三类
- 查看问卷列表、删除
- 填写提交问卷
- 问卷结果列表及结果详情
注:
在系统实现过程中,数据表的设计及数据操作有些麻烦,感兴趣的往下看:
为了问卷结果的可读性及统计方便,数据表设计时将 问卷、问题、选项 分为三个表,在插入、读取问卷时,需要顺序、批量进行数据库操作。
如:新增1个问卷,该问卷有10个问题,单选及多选问题包含2个以上的选项。
那么数据操作顺序是:
- 先插入问卷,并得到返回的问卷ID。
- 得到问卷ID,按顺序插入10个问题,每个问题在插入成功后,返回问题ID。
- 每个问题插入成功时得到问题ID,按顺序插入该问题的多个选项,只有当该问题及问题选项全部插入成功时,开始执行下个问题。
可以看到3是2中的内部循环,2本身是个循环,1和2是顺序执行关系。对于这样的数据插入,如果用常规的嵌套回调,光一个问题就是三层以上的嵌套,几十个问题的话就没法玩了。而且所有的操作只需要一个返回结果,及最终成功与否,只要当其中任何一次插入失败则失败。
最终实现方法是使用async.eachSeries
,以下代码实现上述问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| insertSurvey: function (data,callback) { pool.getConnection(function(err,connection){ if( err ){ callback(err); return; } connection.query( "insert into t_survey(... , ... ,...) values(..., ...)", function(err,res){ if(res){ var surveyId = res.insertId; {...}
async.eachSeries( insertQuestionSql, function(item,questioncb){ connection.query( item.survey, function(err, results) { if(err) { questioncb(err,result); }else{ var questionId = results.insertId; {...}
if( item.data.type == 'radio' || item.data.type == 'checkbox' ){ async.eachSeries( insertOptionSql, function( optionitem, optioncb ){ connection.query( optionitem, function( operror,opresult){ if(operror){ optioncb(operror,opresult); }else{ optioncb( opresult.insertId ); } }); },function(err){ if(err){ callback(err); }else{ callback(); } }); }else{ questioncb(); } } }); },function(err) { callback(err); }); }else if(err){ callback(err) } callback(result); connection.release(); }) }) },
|
最终的解决方案也是三层嵌套回调,也对应了对三个表的操作,暂时算是最优解决方案了。
async.eachSeries
保证了SQL的执行顺序,而且当其中一条执行异常,就不会继续执行下一条,简单示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| var sqls = [ "INSERT INTO log SET data='data1'", "INSERT INTO log SET data='data2'", "INSERT INTO log SET data='data3'" ];
async.eachSeries(sqls, function(item, callback) { connection.query(item, function(err, results) { if(err) { callback(err); } else { console.log(item + "执行成功"); callback(); } }); }, function(err) { if(err) { console.log(err); } else { console.log("SQL全部执行成功"); } });
|