Nodejs之MEAN棧開發(三)---- 使用Mongoose建立模型及API

繼續開扒咱們的MEAN棧開發之路,前面兩節咱們學習了Express、Jade引擎並建立了幾個靜態頁面,最後經過Heroku部署了應用。css

Nodejs之MEAN棧開發(一)---- 路由與控制器html

Nodejs之MEAN棧開發(二)----視圖與模型node

這一節將重點介紹MongoDB以及它的ODM(Object-Document Modeler)Mongoose。MongoDB是一種分佈式文檔存儲型數據庫,和平時使用的關係型數據庫不一樣,它存儲的是BSON格式(json的二進制),特色是高性能、易部署,易使用...(詳情請見百科),主要一點它支持JavaScript讀寫,MEAN棧開發的最大特色就是先後端包括數據庫都是JavaScript編寫。而Mongoose能夠類比EntityFramwork(ORM-對象關係映射),主要作用是讓開發人員能夠更方便的操做數據庫。在開始以前,記得先安裝mongodbjquery

1、MongoDB準備工做git

1. mongo安裝完以後,用cmd切到安裝目錄下面的bin目錄。執行mongo,若是出現版本號則說明啓動成功:

 

若是是出現「計算機積極拒絕」,須要設置下dbpath,也就是指定數據的路徑。程序員

mongod --dbpath=c:\mongodb\db

成功以後,能夠訪問http://localhost:28017/ ,能夠看到以下頁面:github

說明一切就緒。web

2.爲避免每次開機完都要設置dbpath,須要將mongo設置爲服務啓動。分兩步,先用管理員身份打開cmd,切到mongo的bin目錄:

D:\mongodb\bin>mongod --dbpath=D:\mongodb --logpath=D:\mongodb\log.txt --install

以上路徑更換成本身的路徑,而後在運行框中輸入services.msc。設置服務的時候要確保mongo在運行狀態,否則設置不會成功。mongodb

打開文件,找到Mongo DB:數據庫

右鍵選擇啓動,這樣每次開機mongo就會自動運行。

3.更方便點,能夠在桌面建立一個star.bat文件:

@echo off
start "" "D:\mongodb-win32-i386-2.0.6\bin\mongo.exe"

 這樣每次點擊直接進入命令框:

 

4.經常使用命令/基本操做 

查看db:

show dbs

切換到某個數據庫:

switched to db dbname
或者:
use dbname

查看某個數據庫下的集合

show collections

查看集合下面的文檔:

db.collections.find()

 

由於這一節的重點不是要介紹如何在cmd中操做mongo,因此再也不贅述了。更多這樣的細節能夠參考一線碼農的博客:8天學通mongoDB。若是是沒有安裝sp1的電腦,官網的3.0版本安裝成功後沒法運行,能夠用2.xx免安裝版。接下來主要講Mongoose的操做。

2、Mongoose

1.安裝

你能夠用npm直接安裝:

也能夠用vs進行安裝。右鍵工程上的npm,選擇Install New npm Packages。

第一次會下載安裝一個工具,安裝完成以後,搜索Mongoose,出現下面的界面,並安裝。

2.創建鏈接

到這一步環境終因而準備好了,接下來在app_server 文件夾下建立一個models目錄,並新建一個db.js

並在db.js中引用Mongoose:

var mongoose = require('mongoose');

mongodb不須要在鏈接它以前建立數據庫,當第一次鏈接的時候,會根據連接自動建立。Mongoose在鏈接MongoDB的時候會建立一個有五個可重用的鏈接的鏈接池,鏈接數是能夠配置的。這麼作的緣由是由於鏈接數據庫是比較耗時的操做,特別是分佈式的數據庫。鏈接字符串的規則以下:

這裏用戶名、密碼、端口都是能夠省略的,那麼在本地的時候咱們的鏈接字符串就以下:

var dbURI = 'mongodb://localhost/RClub';
mongoose.connect(dbURI);

命名咱們的數據庫爲RClub。Mongoose會基於鏈接的狀態發佈不一樣的事件:

mongoose.connection.on('connected', function () {
    console.log('Mongoose connected to ' + dbURI);
});
mongoose.connection.on('error', function (err) {
    console.log('Mongoose connection error: ' + err);
});
mongoose.connection.on('disconnected', function () {
    console.log('Mongoose disconnected');
});

如此咱們能夠監聽鏈接的狀態。另外應用終止須要監聽nodejs的進程的SIGINT事件。而若是是nodemon重啓,須要監聽的是SIGUSR2事件,以便關閉鏈接。

// 當應用重啓或終止的時候 關閉鏈接
Shutdown = function (msg, callback) {
    mongoose.connection.close(function () {
        console.log('Mongoose disconnected through ' + msg);
        callback();
    });
};

// nodemon 重啓 
process.once('SIGUSR2', function () {
    Shutdown('nodemon restart', function () {
        process.kill(process.pid, 'SIGUSR2');
    });
});

// 應用終止
process.on('SIGINT', function () {
    Shutdown('app termination', function () {
        process.exit(0);
    });
});
View Code

運行nodemon:

顯示鏈接成功!

3.數據模型

Mongoose封裝了mongodb的api使之更便於調用,但做爲MongoDB的對象-文檔建模器,有着更強大的功能。在mongodb中,每個條目就是一個document,至關於關係型數據庫中的行,而document的集合稱爲collection,至關因而關係型數據庫中的table。在Mongoose中定義一個document的對象稱爲schema,至關於用EF定義一個Model,而定義schema中每一條數據的規則稱爲path(約束)。path的規則和jquery.validate.js幾乎是同樣的。

path支持的數據類型以下:

  • String
  • Number
  • Date
  • Boolean
  • Buffer   二進制,好比圖形
  • Mixed  任何類型
  • Array  能夠爲數組,或者內嵌的 子文檔集
  • ObjectId 惟一id

接下來演示下如何用Mongoose建一個數據模型,在models文件夾下建立一個books.js。而後引用Mongoose。以下,更具上一節book對象建立一個bookSchema 。

  {
id: 0, title: "深刻淺出Node.js", info: "樸靈 / 人民郵電出版社 / 2013-12-1 / CNY 69.00", rating: 5, img: "https://img3.doubanio.com/mpic/s27269296.jpg", tags: ["node", "深刻淺出"], brief: '本書從不一樣的視角介紹了 Node 內在的特色和結構。..... ,ISBN: 9787115335500 }

id不用建立,mongo會爲每一個document生成一個惟一的id。

var mongoose = require('mongoose');

var bookSchema = new mongoose.Schema({
    title: String,
    rating: {
        type: Number,
        required: true,
        min: 0,
        max: 5
    },
    info: String,
    img: String,
    tags: [String],
    brief: String,
    ISBN: String
});

這種語法是否是和jquery.validate.js很像,相信不用解釋就能看明白,不知足path的條件時是不能保存或者更改的。每一個path還能夠設置默認值,好比時間:

 createdOn: {
        type: Date,
        default: Date.now
    },

一個Schema能夠包含另外的Schema或數組,在關係型數據庫中這種需求用的是外鍵或者是關係映射表,而Mongoose這樣看起來直觀多了。

var userSchema = new mongoose.Schema({
userName: String,
    email: String,
...});
var commentSchema = new mongoose.Schema({
    user: userSchema,
    ...
    content: String
});
var topicSchema = new mongoose.Schema({
    ....
    visitedCount: { type: Number, default: 0 },
    ...
    comments: [commentSchema],
    deleted: { type: Boolean, default: false },
    top: { type: Boolean, default: false }, // 置頂帖
    ...
});

這個時候的shema 還不具有數據庫的操做能力,還須要註冊下。 

mongoose.model('Book', bookSchema);
mongoose.model('Topic', topicSchema);

所有模型:

var mongoose = require('mongoose');

var bookSchema = new mongoose.Schema({
    title: String,
    rating: {
        type: Number,
        required: true,
        min: 0,
        max: 5
    },
    info: String,
    img: String,
    tags: [String],
    brief: String,
    ISBN: String
});

var userSchema = new mongoose.Schema({
    userName: String,
    email: String,
    password: String,
    createdOn: {
        type: Date,
        default: Date.now
    },
    img: String,
    ip: String,
    mobile: String
});

var commentSchema = new mongoose.Schema({
    user: userSchema,
    createdOn: {
        type: Date,
        default: Date.now
    },
    content: String
});
var topicSchema = new mongoose.Schema({
    title: String,
    type: String,
    visitedCount: { type: Number, default: 0 },
    commentCount: { type: Number, default: 0 },
    createdOn: {
        type: Date,
        default: Date.now
    },
    img: String,
    author: String,
    content: String,
    comments: [commentSchema],
    deleted: { type: Boolean, default: false },
    top: { type: Boolean, default: false }, // 置頂帖
    good: { type: Boolean, default: false }, // 精華帖
});



mongoose.model('Book', bookSchema);
mongoose.model('Topic', topicSchema);
View Code

4.操做數據

接下來就是改造controllers文件夾的中的home.js了,首先要引用db.js和Mongoose。

var db = require('../models/db.js');
var mongoose = require('mongoose');

 1).初始化數據,查詢與新建數據。

 這裏把上一節建立的數據books和topics存入數據庫中:

module.exports.init = function (req, res) {
    mongoose.model('Book').find().exec(function (err, objs) {
        if (err) {
            res.render('error', {
                message: err.message,
                error: err
            });
            return;
        }
        if (objs.length) {
            
            for (var i = 0; i < books.length; i++) {
                var taget = new Bookmodel(books[i]);//建立一個模型
                taget.save(function (err) {//保存。
                    console.log(err);
                });
            }
            
            for (var i = 0; i < topics.length; i++) {
                var taget = new topicmodel(topics[i]);
                console.log('topic create');
                taget.save(function (err) {
                    console.log(err);
                });
            }
            res.send('初始化完成...');
        }
        res.render('books', { title: 'Books', books: objs });
    });

這段代碼裏面有查詢和新建保存,mongoose.model("Book") 至關於EF中的db.Books。而這裏的find()方法並無當即執行,這裏有點像Linq的感受,能夠鏈式查詢:

Book.find({ size: 'small' }).where('createdDate').gt(oneYearAgo).exec(callback);//例子,和上面的book沒有關係

這裏Book至關於mongoose.model("Book") ,而{ size: 'small' }是一個條件。最終到exec方法時才正在執行。回調函數默認有兩個參數,一個是err,一個是結果對象。這裏偷了懶只判斷了books的查詢結果,集合爲空的話就加上原來的數據。由於mongoose.model("Book")使用的比較多,因此乾脆提出來:

var Bookmodel = mongoose.model('Book');
var Topicmodel = mongoose.model('Topic');

find方法是查詢一個集合,經常使用的還有findone:

var query = Person.findOne({ 'name.last': 'Ghost' });
// 選擇name和occupation 字段
query.select('name occupation');

// 執行查詢
query.exec(function (err, person) {
  if (err) return handleError(err);
  console.log('%s %s is a %s.', person.name.first, person.name.last, person.occupation) 
})

保存數據,new一個Model,傳入初始化的對象,save便可。

 var taget = new Bookmodel(books[i]);
      taget.save(function (err) {
               console.log(err);
          });

配置下路由:

router.get('/init', homeController.init);

運行:

所以數據添加成功!

3、app_api

爲方便後面複用,接下來將數據調用換成api的方式。在工程裏面新建一個app_api文件夾,並將原來app_server目錄下的models文件移過去。並增長controllers和routes文件夾。也就是說,把數據調用分離出來。

1)在app.js中增長如下代碼:

var routesApi = require('./app_api/routes/index');
...
app.use('/', routes);
app.use('/api', routesApi);

也就是說,全部以/api/xx開始的請求將由routes/index.js來路由。

2)在routes文件下新增index.js 文件,用來配置api的路由:

var express = require('express');
var router = express.Router();
var bookCtrl = require('../controllers/book');
var topicCtrl = require('../controllers/topic');

router.get('/books', bookCtrl.books);
router.post('/book', bookCtrl.bookCreate);
router.get('/book/:bookid', bookCtrl.bookReadOne);
router.put('/books/:bookid', bookCtrl.bookUpdateOne);
router.delete('/books/:bookid', bookCtrl.bookDeleteOne);

//topics
router.get('/topics', topicCtrl.topics);

module.exports = router;

路由覆蓋了增刪改查,暫時先實現這部分的路由。後面根據需求再增長。

3)controller實現

一個成功的Restful API應該包含返回的數據和http的狀態碼,所以咱們定義了一個公用方法:

var sendJSONresponse = function (res, status, content) {
    res.status(status);
    res.json(content);
};

好比定義一個bookReadOne方法:

module.exports.bookReadOne = function (req, res) {
    var bookid = req.params.bookid;
    if (!bookid) {
        sendJSONresponse(res, 404, {
            "message": "Not found, bookid is required"
        });
        return;
    }
    BookModel.findById(bookid).exec(function (err, book) {
        if (!book) {
            sendJSONresponse(res, 404, {
                "message": "bookid not found"
            });
            return;
        } else if (err) {
            sendJSONresponse(res, 400, err); return;
        }
        console.log(book);
        sendJSONresponse(res, 200, book); 
    });
}

請求成功發送狀態碼200和結果,請求失敗則發送404或者500及錯誤。

books.js:

var mongoose = require('mongoose');
var BookModel = mongoose.model('Book');

var sendJSONresponse = function (res, status, content) {
    res.status(status);
    res.json(content);
};
 

module.exports.books = function (req, res) {
    BookModel.find().exec(function (err, books) {
        if (err) {
            console.log(err);
            sendJSONresponse(res, 400, err);
            return;
        }
        sendJSONresponse(res, 200, books);
    });
}

module.exports.bookCreate = function (req, res) {
    BookModel.create({
        title: req.body.title,
        info: req.body.info,
        img: req.body.img,
        tags: req.body.tags,
        brief: req.body.brief,
        ISBN: req.body.ISBN
    }, function(err, book) {
        if (err) {
            console.log(err);
            sendJSONresponse(res, 400, err);
        } else {
            console.log(book);
            sendJSONresponse(res, 201, book);
        }
    });
}

module.exports.bookReadOne = function (req, res) {
    var bookid = req.params.bookid;
    if (!bookid) {
        sendJSONresponse(res, 404, {
            "message": "Not found, bookid is required"
        });
        return;
    }
    BookModel.findById(bookid).exec(function (err, book) {
        if (!book) {
            sendJSONresponse(res, 404, {
                "message": "bookid not found"
            });
            return;
        } else if (err) {
            sendJSONresponse(res, 400, err);
            return;
        }
        console.log(book);
        sendJSONresponse(res, 200, book);

    });
}

module.exports.bookUpdateOne = function (req, res) {
    var bookid = req.params.bookid;
    if (!bookid) {
        sendJSONresponse(res, 404, {
            "message": "Not found, bookid is required"
        });
        return;
    }
    BookModel.findById(bookid).exec(function (err, book) {
        if (!book) {
            sendJSONresponse(res, 404, {
                "message": "bookid not found"
            });
            return;
        } else if (err) {
            sendJSONresponse(res, 400, err);
            return;
        }
        book.title = req.body.title;
        book.rating = req.body.rating;
        book.info = req.body.info;
        book.img = req.body.img;
        book.tags = req.body.tags;
        book.brief = req.body.brief;
        book.ISBN = req.body.ISBN;
        book.save(function (err, book) {
            if (err) {
                sendJSONresponse(res, 404, err);
            } else {
                sendJSONresponse(res, 200, book);
            }
        });
    });


}

module.exports.bookDeleteOne = function (req, res) {
    var bookid = req.params.bookid;
    if (bookid) {
        BookModel.findByIdAndRemove(bookid)
            .exec(function (err) {
            if (err) {
                console.log(err);
                sendJSONresponse(res, 404, err);
                return;
            }
            console.log("book id :" + bookid + "deleted");
            sendJSONresponse(res, 204, null);
        });
    } else {
        sendJSONresponse(res, 404, { message: "No bookid" });
    }
}
View Code

這樣注意一點是,find()、findbyid和findByIdAndRemove不是當即執行,是在exec方法中執行,可是create,save是當即執行的。

5)、調用api

接下來就是在app_server下的controller中調用上面定義的api。在這裏須要安裝一個request模塊,request讓http請求變的更加簡單。

 在home.js中引用request:

var request = require('request');

request的調用以下:

request(options, callback)

包含options和回調兩部分,options結構以下,包含url,method,json和qs四部分。

var requestOptions = {
url : "http://yourapi.com/api/path",
method : "GET",
json : {}, //請求體的JavaScript對象
qs : {
offset : 20 //查詢字符串
}
};

而默認的回調格式以下:

function(err, response, body) {
if (err) {
console.log(err);
} else if (response.statusCode === 200) {
console.log(body);
} else {
console.log(response.statusCode);
}
}

修改index方法,先定義一個apiOptions,只想默認路徑,記得在發佈的時候修改成帶域名的地址。

var apiOptions = {
    server : "http://localhost:3000"
};

module.exports.index = function (req, res) {
    var requestOptions, path;
    path = "/api/topics";
    requestOptions= {
        url: apiOptions.server + path,
        method: "GET",
        json:{},
    }
    request(requestOptions, function (err, response, body) {
        if (response.statusCode == 200) {
            res.render('index', { title: 'Index', topics: body });
        } else {
            res.render('error', { message: err.message, error: err });
        }
    });
};

這樣就進行了分離,home.js不在須要引用Mongoose部分。

home.js:

var request = require('request');

var apiOptions = {
    server : "http://localhost:3000"
};
//if (process.env.NODE_ENV === 'production') {
//    apiOptions.server = "https://stoneniqiu-mean.herokuapp.com/ ";
//}


module.exports.index = function (req, res) {
    var requestOptions, path;
    path = "/api/topics";
    requestOptions= {
        url: apiOptions.server + path,
        method: "GET",
        json:{},
    }
    request(requestOptions, function (err, response, body) {
        if (response.statusCode == 200) {
            res.render('index', { title: 'Index', topics: body });
        } else {
            res.render('error', { message: err.message, error: err });
        }
    });
};

module.exports.books = function (req, res) {
    var requestOptions, path;
    path = "/api/books";
    requestOptions = {
        url: apiOptions.server + path,
        method: "GET",
        json: {},
    }
    request(requestOptions, function (err, response, body) {
        if (response.statusCode == 200) {
            res.render('books', { title: 'Books', books: body });
        } else {
            res.render('error', { message: err.message, error: err });
        }
    });
};



module.exports.detail = function (req, res) {
    var requestOptions, path;
    path = "/api/book/" + req.params.id;
    requestOptions = {
        url: apiOptions.server+path ,
        method: "GET",
        json: {},
    }
    request(requestOptions, function (err, response, body) {
        if (response.statusCode == 200) {
            res.render('detail', { title: body.title, book: body });
        } else {
            res.render('info', err);
        }
    });
   
   };

module.exports.about = function (req, res) {
    res.render('about', { title: 'About' });
};



 
View Code    

更多查詢能夠移步:http://mongoosejs.com/docs/queries.html

在首頁,須要處理一下時間顯示的問題,增長了一個mixin

mixin formatDate(dateString)
  -var date = new Date(dateString);
  -var d = date.getDate();
  -var monthNames = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12" ];
  -var m = monthNames[date.getMonth()];
  -var y = date.getFullYear();
  -var output = y + '/' + m + '/' + d;
  =output

調用:

   span.pull-right
           +formatDate(topic.createdOn)

頁面以下:

初步改造完成。以前還寫了一個基於回調的service方式的controller和service,相似於C#中的分離。後來以爲仍是api的方式更好,留在這裏能夠當一個參考。

home.js:

var bookservice = require('../services/homeService.js');
 
module.exports.index = function (req, res) {
    bookservice.allTopics(function (result) {
        var obj = result.content;
        console.log(obj.status);
        if (result.status == 200) {
            res.render('index', { title: 'Index', topics: obj });
        }
        res.render('info', obj);
    });  
};

module.exports.books = function (req, res) {
    bookservice.allBooks(function(result) {
        var obj = result.content;
        console.log(obj.status);
        if (result.status == 200) {
            res.render('books', { title: 'Books', books: obj });
        }
        res.render('info', obj);
    });  
};



module.exports.detail = function (req, res) {
    bookservice.bookReadOne(req.params.id, function (result) {
        var obj = result.content;
        if (result.status == 200) {
            res.render('detail', { title: obj.title, book: obj });
        } 
        res.render('info', obj);
    });
   };

module.exports.about = function (req, res) {
    res.render('about', { title: 'About' });
};



 
View Code

homeService.js:

var mongoose = require('mongoose');
var db = require('../models/db.js');
var Bookmodel = mongoose.model('Book');
var Topicmodel = mongoose.model('Topic');


var jsonResult = function (status, content) {
    return { status: status, content: content };
};

module.exports.bookReadOne = function (id,callback) {
    console.log('Finding book details', id);
    if (!id) {
        console.log('No bookid specified');
        return jsonResult(404, { "message": "No bookid specified" });
    }
    Bookmodel.findById(id).exec(function (err, book) {
        if (err) {
            callback(jsonResult(404, err));
            return;
        }
        if (!book) {
            callback(jsonResult(404, { "message": "book not found" }));
            return;
        }
       callback(jsonResult(200, book));
    });

};
module.exports.allBooks=function(callback) {
    Bookmodel.find().exec(function (err, books) {
        if (err) {
            callback(jsonResult(404, err));
            return;
        }
        if (!books.length) {
            callback(jsonResult(404, { "message": "books not found" }));
            return;
        }
        callback(jsonResult(200, books));
    });
}
module.exports.createBook = function (book, callback) {
    var t = new Bookmodel(book);
    t.save(function (err) {
        callback(err);
    });
}

module.exports.allTopics=function(callback) {
    Topicmodel.find().exec(function (err, topics) {
        if (err) {
            callback(jsonResult(404, err));
            return;
        }
        if (!topics.length) {
            callback(jsonResult(404, { "message": "topics not found" }));
            return;
        }
        callback(jsonResult(200, topics));
    });
}

module.exports.createTopic=function(topic, callback) {
    var t = new Topicmodel(topic);
    t.save(function(err) {
        callback(err);
    });
}


var books = [
    {
        id: 0,
        title: "深刻淺出Node.js",
        info: "樸靈 / 人民郵電出版社 / 2013-12-1 / CNY 69.00",
        rating: 5,
        img: "https://img3.doubanio.com/mpic/s27269296.jpg",
        tags: ["node", "深刻淺出"],
        brief: '本書從不一樣的視角介紹了 Node 內在的特色和結構。由首章Node 介紹爲索引,涉及Node 的各個方面,主要內容包含模塊機制的揭示、異步I/O 實現原理的展示、異步編程的探討、內存控制的介紹、二進制數據Buffer 的細節、Node 中的網絡編程基礎、Node 中的Web 開發、進程間的消息傳遞、Node 測試以及經過Node 構建產品須要的注意事項。最後的附錄介紹了Node 的安裝、調試、編碼規範和NPM 倉庫等事宜。本書適合想深刻了解 Node 的人員閱讀。'
        ,ISBN: 9787115335500
    },
    {
        id: 1,
        title: "程序員修煉之道 : 從小工到專家",
        info: "Andrew Hunt、David Thomas / 馬維達 / 電子工業出版社 / 2005-1 / 48.00元",
        rating: 5,
        img: "https://img3.doubanio.com/mpic/s3957863.jpg",
        tags: ["程序人生", "軟件開發"],
        brief: '《程序員修煉之道》由一系列的獨立的部分組成,涵蓋的主題從我的責任、職業發展,直到用於使代碼保持靈活、而且易於改編和複用的各類架構技術。利用許多富有娛樂性的奇聞軼事、有思想性的例子以及有趣的類比,全面闡釋了軟件開發的許多不一樣方面的最佳實踐和重大陷阱。不管你是初學者,是有經驗的程序員,仍是軟件項目經理,本書都適合你閱讀。'
        ,ISBN: 9787505397194
    },
    {
        id: 2,
        title: "Getting MEAN with Mongo, Express, Angular, and Node",
        info: "Simon Holmes / Manning Publications / 2015-11-26 / USD 44.99",
        rating: 4,
        img: "https://img3.doubanio.com/mpic/s27676844.jpg",
        tags: ["node", "web開發", "編程"],
        brief: 'MEAN棧開發,比較詳盡的的應用開發書籍'
        , ISBN: 9781617292033
    }
];
var topics = [
    {
        title: "書山有路第十一期:程序員修煉之道-第二章-注重實效的途徑--第五天",
        type: "讀書",
        visitedCount: 80,
        commentCount: 2,
        createdOn: '2016/5/15 21:32',
        author: 'stoneniqiu',
        img: 'http://upload.jianshu.io/users/upload_avatars/133630/d5370e672fd4.png?imageMogr/thumbnail/90x90/quality/100'
    },
    {
        title: "《明朝那些事兒》之閒言散語",
        type: "書評",
        visitedCount: 180,
        commentCount: 20,
        createdOn: '2016/5/15 21:32',
        author: '卡卡卡薩布蘭卡 ',
        img: 'http://upload.jianshu.io/users/upload_avatars/1675188/2d0810ccc03d.jpg?imageMogr/thumbnail/90x90/quality/100'
    },
    {
        title: "有《程序員修煉之道》高清版嗎?",
        type: "求書",
        visitedCount: 90,
        commentCount: 1,
        createdOn: '2016/5/15 21:32',
        author: '吾不知 ',
        img: 'http://upload.jianshu.io/users/upload_avatars/1125491/3910f3825f73.jpg?imageMogr/thumbnail/90x90/quality/100',
    },
    {
        title: "《國富論》-讀書筆記",
        type: "書評",
        visitedCount: 180,
        commentCount: 20,
        createdOn: '2016/5/15 21:32',
        author: '尋海 '
        ,img: 'http://upload.jianshu.io/users/upload_avatars/133630/d5370e672fd4.png?imageMogr/thumbnail/90x90/quality/100'
    },
    {
        title: "《高效人士的七個習慣》讀書筆記",
        type: "書評",
        visitedCount: 180,
        commentCount: 20,
        createdOn: '2016/5/15 21:32',
        author: '書蟲紀慶 ',
        img: 'http://upload.jianshu.io/users/upload_avatars/1429280/454c495361f9.jpg?imageMogr/thumbnail/90x90/quality/100'
    },
    {
        title: "《css揭祕》這本書如何",
        type: "求索",
        visitedCount: 58,
        commentCount: 3,
        createdOn: '2016/5/15 21:32',
        author: 'Watery_D_Lotus ',
        img: 'http://upload.jianshu.io/users/upload_avatars/1449533/a2d98762484a.jpg?imageMogr/thumbnail/90x90/quality/100'
    }
];



//module.exports.bookCreate = function (req, res) {
//    var book = {
//        title: "test",
//        info: "Simon Holmes / Manning Publications / 2015-11-26 / USD 44.99",
//        rating: 4,
//        img: "https://img3.doubanio.com/mpic/s27676844.jpg",
//        tags: ["node", "web開發", "編程"],
//        brief: 'MEAN棧開發,比較詳盡的的應用開發書籍',
//        ISBN: 9781617292033
//    };
//    var b = new Bookmodel(book);
//    b.save(function (err) {
//        if (err) {
//            console.log(err);
//            res.render('error', {
//                message: err.message,
//                error: err
//            });
//        }
//        res.render('info', { message: "添加成功!", success: true });
//    });

//};
//module.exports.bookDelete = function (req, res) {
//    Bookmodel.findOneAndRemove({ title: "test" }, function (err) {
//        if (err) {
//            console.log(err);
//            res.render('error', {
//                message: err.message,
//                error: err
//            });
//        }
//        res.render('info', { message: "刪除成功!", success: true });
//    });
//};
View Code

至此,這三個頁面的數據所有都是經過api從數據庫中獲取。那麼如今咱們要發佈,本地數據庫顯然是不行。那怎麼辦呢?

4、mlab,500M MongoDB免費空間!

 mlab是一個提供部署在雲端的mongodb數據庫服務平臺,能夠對每一個用戶免費提供500M空間。

 1. 先註冊一個帳號:https://mlab.com/,並驗證郵箱:

 2.點擊Create new建立數據庫:這裏選擇亞馬遜的單用戶sanbox會有免費的500M空間。

 輸入數據庫名稱,並建立

3.建立成功以後,給數據庫建立一個用戶

 4.鏈接字符串: 

 第一個字符串是用cmd鏈接,第二個用於咱們的程序。修改db.js 鏈接成功:

但記得初始化數據。到這裏這一節就基本結束了。更多細節能夠參考:

源碼:https://github.com/stoneniqiu/ReadingClub/tree/mongoose

訪問地址:https://stoneniqiu-mean.herokuapp.com/

小結:這一節篇幅有點長,整理了五六個小時,主要涉及了mongodb的基本操做和安裝服務相關;Mongoose的建模以及使用Mongoose進行增刪改查;以及api的封裝和調用;最後介紹了mlab,來把mongodb部署到雲端。這樣咱們繼續可使用heroku發佈。文中的操做所覆蓋的api操做可能不全面,這個你們能夠去根據須要去參考官方文檔。下一節講解form提交、驗證以及文件上傳。

相關文章
相關標籤/搜索