zoukankan      html  css  js  c++  java
  • 用“MEAN”技术栈开发web应用(三)用mongodb搭建数据库

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

    mongodb的安装和启动

    首先我们得安装mongodb,先去官网( http://www.mongodb.org/downloads)下载安装包,我的开发环境是Windows,所以下载Windows下的iso文件,根据提示一路安装完毕即可,没什么需要特别选择的。
    安装完后,为了能在cmd中全局都能启动mongodb,我们需要配置环境变量,将安装目录下的bin目录配置在系统变量中,如图:
    接下来,新建一个目录,用于存放数据库文件。我新建的目录为D:mongodbdatadb,然后运行cmd,执行命令mongod --dbpath D:mongodbdatadb,这个时候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
    另外,本系列文章只是一个入门级别的介绍,所写的代码以及数据库的设计基本上都属于”玩具代码“,写一个自己玩的项目还行。在实际的项目中,我们还得考虑各种因素,性能、负载等等,更多话题有待研究。
  • 相关阅读:
    LaTeX表格紧跟文字 (不影响下方文本对齐)
    latex减少图片和图片解释文字之间的距离、调整公式与正文间距离,调整空白大小:
    请收藏,Linux 运维必备的 40 个命令总结,收好了~
    将公式直接转化为Latex代码的神器-Mathpix Snip
    if __name__ == '__main__':的作用和原理【转】
    PyCharm,Terminal 常用快捷键
    Python包中 __init__.py文件的作用
    pycharm写代码光标变成了黑框
    客户端链接Blog
    Sublime 中文标题乱码
  • 原文地址:https://www.cnblogs.com/lvdabao/p/mean-techstack-mongodb.html
Copyright © 2011-2022 走看看