上一篇介绍了如何用express搭建起服务端MVC的开发架构,本篇我们来详细介绍一下这个Model层,也就是数据库访问层。包含如何使用mongodb搭建数据库,以及如何使用mongoose来访问数据。
 

mongodb的安装和启动

首先我们得安装mongodb,先去官网( http://www.mongodb.org/downloads)下载安装包,我的开发环境是Windows,所以下载Windows下的iso文件,根据提示一路安装完毕即可,没什么需要特别选择的。
安装完后,为了能在cmd中全局都能启动mongodb,我们需要配置环境变量,将安装目录下的bin目录配置在系统变量中,如图:
接下来,新建一个目录,用于存放数据库文件。我新建的目录为D:\mongodb\data\db,然后运行cmd,执行命令mongod --dbpath D:\mongodb\data\db,这个时候mongodb就运行起来了,我们就可以用程序来连接数据库了。
 

连接数据库

mongodb的默认端口是27017,我们在项目中有一个models文件夹,里面放置与数据库连接的数据模型,其中有一个mongodb.js,内容很简单:
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/QuestionMaker');
exports.mongoose = mongoose;
是标准的commonjs模块写法,先引用mongoose模块,然后连接数据库,对外暴露mongoose模块。可以看到我们在代码中去访问本地的QuestionMaker数据库。那么首先我们得有这个数据库才行。运行cmd,创建一个数据库
use QuestionMaker
db.createCollection("counters")
此命令会创建一个名为QuestionMaker的数据库,并在该库创建一个集合counters(这个集合我们后续会用到),必须得这么写,否则数据库无法创建。驱动模块写好了,我们在其他模块中引用该模块后,就可以连接到数据库了。
 

使用mongoose操作数据库

我们看到上面用了一个叫做mongoose的模块,它是一个nodejs模块,mongoose提供了Schema、Model、Documents对象,用它可以更加直观的操作数据库,所以很多人喜欢这个模块,我们项目中也用它来操作数据库。
为了能以我们熟悉的面向对象的方式来访问数据库,我们先根据试题的数据结构来创建一个Schema:
var QuestionSchema = new Schema({
id: String,
qtype: Number,
name: String,
content: String,
options: [
{
name: String
}
],
answer: String
});
Schema可以理解为一个模板,根据此模版,我们可以用mongoose.model来创建出一个Question类,代码如下:
var Question = mongodb.mongoose.model("Question", QuestionSchema);
利用Question类示例化出的对象带有很多方法用来访问/操作数据库,如save方法,可以保存一条文档,也就是document(mongodb中的概念,类似我们以前概念中的一条记录)。
为了尽可能少的对外暴露数据(封装性),我新建了一个QuestionDAO对象,也就是仿造java中的概念,加一个DAO层,用来提供数据访问。对外暴露的方法都定义在这个对象上,例如保存记录和更新记录的代码如下:
//保存试题
QuestionDAO.prototype.save = function(obj, callback){
var instance = new Question(obj);
instance.save(function(err){
callback(err, null);
});
} //更新试题
QuestionDAO.prototype.update = function(obj, callback){
Question.findByIdAndUpdate(obj._id, obj, {}, function(err){
callback(err, null);
});
}
用了mongoose提供的save方法和findByIdAndUpdate方法,每一个操作之后都可以传回调函数,这样我们就能把数据库访问的结果返回给controller层了。
另外,根据业务需求,我们就可以写更多的方法了,如项目中的list、get、remove,分别用来获取试题列表、获取试题、删除试题。其中list方法中还实现了分页返回数据。
 

mongodb实现id自增

id自增是数据库的一个常见需求,在mysql中,只要指定字段auto_increment即可,在mongodb中,没有这样的方法,所以必须得在代码中实现才行。我们按照官方给出的解决方法,实现questions集合的id自增。
id自增功能需要一个辅助的集合来完成,就是我们之前新建好的counters,用来记录当前的id值为多少。在mongodb命令行中执行db.counters.save({_id: "questionid", seq: 0})完成初始化。_id是mongodb默认提供的一个字段,我们这里赋值为questionid,是为了做一个标记,以便在后面能够查找出这条记录。
然后在question.js中创建CounterSchema并生成一个Counter类,用来操作counters集合,代码如下:
var CounterSchema = Schema({
_id: {type: String, required: true},
seq: { type: Number, default: 1 }
}); var Counter = mongodb.mongoose.model("Counter", CounterSchema);
然后,在QuestionSchema的save方法之前,我们应该先去counters中获取最新id,可以用pre方法来实现,代码如下:
QuestionSchema.pre('save', function(next) {
var doc = this;
Counter.findByIdAndUpdate({_id: 'questionid'}, {$inc: { seq: 1} }, function(error, counter) {
if(error)
return next(error);
doc.id = counter.seq;
next();
});
});
QuestionSchema.set('toObject', { getters: true });
如此一来,每次Question执行save方法的时候,都会调用这个函数,从而获取到递增后的最新id。
 

备份和导入

数据库的备份和导入当然是必不可少了,比如大家可以拿这我的备份文件直接导入来练习,这样就省去了一步一步创建的步骤。
备份数据库可以使用mongodump命令,用法如下:
mongodump -h dbhost -d dbname -o dbdirectory
导入已有的数据库可以使用mongostore命令,用法如下:
mongorestore -h dbhost -d dbname –directoryperdb dbdirectory
具体的参数可以在网上搜索,文章很多,此处不再详细说明。
 

客户端工具

mongodb有没有像mysql那样的客户端工具呢?当然有啦,我使用的是robomongo这个工具,简单好用,界面如下,大家可以尝试使用。
 
使用MEAN技术栈开发web应用系列三部曲就到这里了,再次附上练手项目的地址:https://github.com/Double-Lv/QuestionMaker
另外,本系列文章只是一个入门级别的介绍,所写的代码以及数据库的设计基本上都属于”玩具代码“,写一个自己玩的项目还行。在实际的项目中,我们还得考虑各种因素,性能、负载等等,更多话题有待研究。

用“MEAN”技术栈开发web应用(三)用mongodb搭建数据库的更多相关文章

  1. 用“MEAN”技术栈开发web应用(一)AngularJs前端架构

    前言 不知何时突然冒出“MEAN技术栈”这个新词,听起来很牛逼的样子,其实就是我们已经熟悉了的近两年在前端比较流行的技术,mongodb.express.angularjs.nodejs,由于这几项技 ...

  2. “MEAN”技术栈开发web应用

    “MEAN”技术栈开发web应用 上一篇我们讲了如何使用angular搭建起项目的前端框架,前端抽象出一个service层来向后端发送请求,后端则返回相应的json数据.本篇我们来介绍一下,如何在no ...

  3. 用“MEAN”技术栈开发web应用(二)express搭建服务端框架

    上一篇我们讲了如何使用angular搭建起项目的前端框架,前端抽象出一个service层来向后端发送请求,后端则返回相应的json数据.本篇我们来介绍一下,如何在nodejs环境下利用express来 ...

  4. Spring Security技术栈开发企业级认证与授权(一)环境搭建

    本项目是基于慕课网的Spring Security技术栈开发企业级认证与授权,采用IDEA开发,本文章用来记录该项目的学习过程. 慕课网视频:https://coding.imooc.com/clas ...

  5. Python全栈开发【基础三】

    Python全栈开发[基础三]  本节内容: 函数(全局与局部变量) 递归 内置函数 函数 一.定义和使用 函数最重要的是减少代码的重用性和增强代码可读性 def 函数名(参数): ... 函数体 . ...

  6. 基于.Net进行前端开发的技术栈发展路线(三)

    前言 上一篇<我的技能树二>文章分享了我的技能中的前端技能和Java技能,今天继续跟大家分享的就是后端技能了. 我的技能树 我当前的技能树: 其中,标注为黄色旗帜的是基本掌握,标注为红色旗 ...

  7. web技术栈开发原生应用-多端共用一套代码

    weex: vuejs开发原生应用 nativescript: vuejs开发原生应用 ReactNative = reactjs开发原生应用 ionic = angularjs 开发原生应用

  8. Python全栈开发-web框架之django

    一:web框架 什么是web框架? Web应用框架(Web application framework)是一种开发框架,用来支持动态网站.网络应用程序及网络服务的开发.这种框架有助于减轻网页开发时共通 ...

  9. CefSharp-基于C#的客户端开发框架技术栈开发全记录

    CefSharp简介 源于Google官方 CefSharp用途 CefSharp开发示例 CefSharp应用--弹窗与右键 不弹出子窗体 禁用右键 CefSharp应用--High DPI问题 缩 ...

随机推荐

  1. 用goto做异常处理

    http://www.cnblogs.com/trying/archive/2012/06/25/2863753.html 今天在CSDN上看到的关于错误返回值的讨论,感觉非常有趣. 从中可以看出被教 ...

  2. I Could Have Danced All Night

    百老汇著名音乐剧<窈窕淑女(My Fair Lady)>中脍炙人口的经典歌曲. Bed, bed ,I couldn't go to bed床,床,我不能上床去 My head's too ...

  3. 使用Spring发送带附件的电子邮件(站内和站外传送)

    JavaMail的介绍 JavaMail,顾名思义,提供给开发者处理电子邮件相关的编程接口.它是Sun发布的用来处理email的API.它可以方便地执行一些常用的邮件传输.   虽然JavaMail是 ...

  4. centos配置虚拟主机

    首先注释掉 DocumentRoot /var/www/html 然后添加如下代码至文件底部:       NameVirtualHost 192.168.0.3     <virtualhos ...

  5. Tomat简介

    Tomcat目录结构bin: 存放各种平台下启动和关闭Tomcat的脚本文件.startup.bat是windows下启动tomcat的文件,shutdown.bat是关闭tomcat的文件.comm ...

  6. Puppet自动化运维-资源介绍篇(4)

    1.什么是资源? 资源是Puppet最基础的元素,每个资源的定义都具有标题,类型,以及一系列的属性. 资源定义有如下的特性:   (1) Puppet使用title在编译时区分每个资源,使用命名变量在 ...

  7. Netty参数配置表

  8. mysql优化笔记之分页

    过年闲得蛋疼,于是看看mysql优化,看了网上好多关于分页的优化方法,但是呢,我亲自试上一把的时候,没有出现他们说的现象...难道是我的机器问题么? 下面看看我的实践记录,希望看到的加入进来交流一下O ...

  9. php sprintf 函数的用法

    sprintf() 函数把格式化的字符串写入变量中. arg1.arg2.++ 参数将被插入到主字符串中的百分号(%)符号处.该函数是逐步执行的.在第一个 % 符号处,插入 arg1,在第二个 % 符 ...

  10. bzoj1051Tarjan裸题

    tarjan缩点+判断出度为0的点 所以不需要新建边 #include <cstdio> ,time=,T=,sum=,ans=; ],to[],nex[],fir[],dfn[],low ...