原文: http://cwbuecheler.com/web/tutorials/2013/node-express-mongo/
太多的教程教你些一個Hello, World!了, 但是僅憑Hello, World! 是找不到工作的, 因此有了這篇教程.
PART I – 安裝開發環境
作者是在Windows 8上開發的.
STEP 1 – 安裝NODE.JS
打開 Node.js website 點擊綠色的安裝按鈕. 運行安裝程序就安裝好了, 就是這么簡單. 現在你已經安裝好Node.js了, 同樣NPM(Node Package Manager)也安裝好了
- 打開命令終端 cmd
- cd到你想要建立應用的目錄
(本教程是 C:\node).
STEP 2 – 安裝EXPRESS
現在我們安裝Express, Express是一個框架他能讓我們更簡單的建立一個web應用. 在命令終端運行:
C:\node>npm install -g express
(-g代表安裝到全局, 我感覺express不應該安裝到全局)
好消息: 你可以安裝一個express的"generator". 他能幫我們生成一個網站基本的框架, 讓我們少些了好多的代碼(如果你想了解更多可以去Yeoman 看看). 安裝generator也很容易, 在命令終端運行:
C:\node>npm install -g express-generator
好了是時候生成一個網站的基本框架了
STEP 3 – CREATE AN EXPRESS PROJECT
我們使用Express 和 Jade, 在命令終端輸入:
C:\node>express nodetest1
點擊回車, 你可以看到下面的東西
C:\node>express nodetest1
create : nodetest1
create : nodetest1/package.json
create : nodetest1/app.js
create : nodetest1/public
create : nodetest1/public/javascripts
create : nodetest1/public/images
create : nodetest1/routes
create : nodetest1/routes/index.js
create : nodetest1/routes/users.js
create : nodetest1/public/stylesheets
create : nodetest1/public/stylesheets/style.css
create : nodetest1/views
create : nodetest1/views/index.jade
create : nodetest1/views/layout.jade
create : nodetest1/views/error.jade
create : nodetest1/bin
create : nodetest1/bin/www
install dependencies:
$ cd nodetest1 && npm install
run the app:
$ DEBUG=my-application ./bin/www
STEP 4 – 編輯依賴
現在我們的網站已經有一個基本的結構了, 但是我們現在還有一些事沒做. 你能注意到nodetest1目錄有一個叫package.json的文件. 文件的內容如下:
{
"name": "application-name",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node ./bin/www"
},
"dependencies": {
"express": "~4.0.0",
"serve-favicon": "~2.1.3",
"morgan": "~1.0.0",
"cookie-parser": "~1.0.1",
"body-parser": "~1.0.0",
"debug": "~0.7.4",
"jade": "~1.3.0"
}
}
這些json內容描述了我們的網站和他的一些依賴. 我們需要添加一些東西. 現在讓我們在依賴里面添加MongoDB和Monk.
"dependencies": {
"express": "~4.0.0",
"serve-favicon": "~2.1.3",
"morgan": "~1.0.0",
"cookie-parser": "~1.0.1",
"body-parser": "~1.0.0",
"debug": "~0.7.4",
"jade": "~1.3.0",
"mongodb": "*",
"monk": "*"
}
STEP 5 – 安裝依賴
現在我們已經定義了我們的依賴. 注意星號代表獲取最新的版本. 打開終端 cd到nodetest1目錄, 輸入:
C:\node\nodetest1>npm install
現在終端會輸出一大堆的東西. 因為讀取JSON文件安裝我們定義的依賴對象. 運行完后, 你可以發現一個node_modules目錄, 里面包含了我們之前定義的依賴.
現在你的網站基本可以運行了. 在運行前我們需要設置一個數據庫目錄. 在終端輸入:
C:\node\nodetest1>mkdir data
這個目錄用來存儲我們的MongoDB數據. 如果這個目錄不存在的話, 數據庫會阻塞我們的網站. 好了現在我們可以來運行看看我們的網站了. 在終端輸入:
C:\node\nodetest1>npm start
回車后, 你可以在終端看到下面的東西
> application-name@0.0.1 start D:\sites\node\nodetest1 > node ./bin/www
打開瀏覽器, 輸入http://localhost:3000 你可以看到一個Express的歡迎頁面

PART 2 – 好了讓我們做個"HELLO, WORLD!"
用IDE打開app.js, 內容如下:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var users = require('./routes/users');
上面的代碼給package、依賴、node functionality和路由創建了相應的變量. 路由是modles和controllers的一種關聯. 這里我們忽略不去管user路由只關注於頂級路由 (c:\node\nodetest1\routes\index.js).
app.js
var app = express();
這個非常重要. 他實例化了一個Express並且分配給了app變量. 下面的代碼片段使用這個變量配置一堆express的東西.
app.js
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
上面的代碼告訴app去哪查找views(視圖), 使用何種視圖引擎展現我們的視圖(Jade), 另外調用了一些方法. 倒數第三行代碼告訴Express靜態文件放在public目錄, 我們獲取這些靜態文件的時候不需要在url中輸入public . 比如, 圖片目錄在c:\node\nodetest1\public\images, 但是我們通過http://localhost:3000/images 來進入到圖片目錄.
app.js
/// catch 404 and forwarding to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
/// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
這里有兩種錯誤處理器, 一個是給開發環境用的,另一個是給生產環境使用的.
app.js
module.exports = app;
Node的一個核心部分就是module.exports. 我們的主app導出app對象.
我們先看看app.js現有的路由:
app.use('/', routes);
app.use('/users', users);
上面的代碼告訴Express使用那些路由文件. 一般我提倡為應用的不同部分寫對應的路由文件. 例如, users路由文件可能包含添加用戶、刪除用戶、更新用戶的路由,locations路由文件處理添加、刪除、編輯、展示location的路由. 在我們的這個教程中, 為了簡單的演示, 我們只關注index路由.
Express generator已經定義了一個"routes" 變量指向index路由. 我們在index路由中添加"helloworld"方法展示一個新的頁面. 打開index.js:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res) {
res.render('index', { title: 'Express' });
});
module.exports = router;
在最后一行前加入下面的代碼:
/* GET Hello World page. */
router.get('/helloworld', function(req, res) {
res.render('helloworld', { title: 'Hello, World!' })
});
現在我們還沒創建一個helloworld頁面. 打開views文件夾, 打開index.jade. 創建一個helloworld.jade文件內容拷貝index.jade的內容.
現在helloworld.jade的內容如下:
extends layout
block content
h1= title
p Welcome to #{title}
使用("extends") 將layout.jade作為一個模板, 接下來在layout文件定義的content block下面輸出一個h1和p標簽. 注意"title"參數是我們在index.js路由中已經定義了的.
下面讓我們改變p的內容:
p Hello, World! Welcome to #{title}
保存文件,回到終端, 按ctrl-c退出服務, 輸入:
npm start
順便說一下, 修改Jade模板不需要重啟服務, 但是修改app.js或者路由這樣的.js文件需要重啟服務.
現在打開http://localhost:3000/helloworld 頁面, 效果如下:

PART 3 – 創建數據庫
STEP 1 – 安裝MONGODB
打開http://mongodb.org/ 下載Mongo. 你會得到一個zip文件, 解壓到一個臨時的目錄. 創建一個目錄放Mongo, 把解壓后的文件放到這個新的目錄下.
STEP 2 – 運行MONGOD和MONGO
在你的nodetest1目錄, 新建一個data子目錄. 先cd到你安裝mongo的目錄, 然后輸入:
mongod --dbpath c:\node\nodetest1\data
Mongo服務運行了. 第一次會消耗一定的時間, 因為mongo要預先分配一些空間, 另外還要運行一些任務. 當看到終端輸出"[initandlisten] waiting for connections on port 27017", 這代表啟動完成了. 現在另開一個終端cd到mongo的安裝目錄, 輸入:
mongo
回車后看到下面的內容
c:\mongo>mongo MongoDB shell version: 2.4.5 connecting to: test
這告訴你連接已經建立好了
STEP 3 – 創建數據庫
"connecting to: test" …test是mongo默認使用的數據庫. 其實這個時候還沒有真正的創建了一個名為test的數據庫, 除非你給test創建了一條記錄, 這個時候test數據庫才真正的被創建. 在Mongo console 中輸入:
use nodetest1
現在我們使用"nodetest1數據庫, 和上面講到的"test"一樣, 這個時候我們並沒有真正的創建了nodetest1數據庫. 為了真正的創建這個數據庫, 我們應該添加一些數據.
STEP 4 – 添加數據
添加一些數據到我們的collection. 在這個教程中, 我們的數據比較簡單, 只需要一個username和email.數據格式如下:
{
"_id" : 1234,
"username" : "cwbuecheler",
"email" : "cwbuecheler@nospam.com"
}
在mongo終端輸入:
db.usercollection.insert({ "username" : "testuser1", "email" : "testuser1@testdomain.com" })
這里要注意的是: "db" 代表我們的數據庫, 這里是我們上面定義的"nodetest1"."usercollection" 是我們的collection. 注意我們沒有一個創建usercollection的步驟. 因為第一次使用的時候他會自動被創建.回車. 如果一切順利的話, 終端不會輸出任何東西. 現在輸入:
db.usercollection.find().pretty()
.pretty() 方法會使得輸出自動換行, 這樣返回的內容的可讀性更好. 返回內容如下:
{
"_id" : ObjectId("5202b481d2184d390cbf6eca"),
"username" : "testuser1",
"email" : "testuser1@testdomain.com"
}
現在我們一次插入多條記錄
newstuff = [{ "username" : "testuser2", "email" : "testuser2@testdomain.com" }, { "username" : "testuser3", "email" : "testuser3@testdomain.com" }]
db.usercollection.insert(newstuff);
是的, 我們可以傳遞一個對象數組給我們的collection
STEP 5 – HOOK MONGO UP TO NODE
讓我們開始創建一個頁面顯示數據路里面的內容. 這里是我們期望的得到的html
<ul>
<li><a href="mailto:testuser1@testdomain.com">testuser1</a></li>
<li><a href="mailto:testuser2@testdomain.com">testuser2</a></li>
<li><a href="mailto:testuser3@testdomain.com">testuser3</a></li>
</ul>
我們需要在app.js文件中添加幾行代碼, 用來連接我們的MongoDB. 打開app.js文件:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
現在讓我們來添加3行代碼
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
// New Code
var mongo = require('mongodb');
var monk = require('monk');
var db = monk('localhost:27017/nodetest1');
這幾行代碼告訴我們的應用我們想使用MongoDB, 這里使用的是Monk(現在Mongoose比較流行), 我們的數據庫位於localhost:27017/nodetest1. 注意27017是MOngoDB的默認端口. 現在看到app.js文件的底部, 代碼如下:
app.use('/', routes);
app.use('/users', users);
在這我們需要做點工作.app.use語句是為Express建立中間件. 簡短的說: 他們提交了一些自定義的函數使得你的app更加有用. 他們很簡單, 但是要注意的是他們必須放在路由定義前才能生效.
在上面兩行代碼前加入下面的代碼
// Make our db accessible to our router
app.use(function(req,res,next){
req.db = db;
next();
});
注意: 如果你不是將上面的代碼放在 app.use('/', routes) 之上, 你新加的代碼就不會起作用.
當我們添加Mongo和Monk到app.js的時候我們已經定義了db. db是我們的Monk連接對象. 在把上面的代碼添加到app.use后, 每個HTTP request對象都有一個db了. 注意: 這個對性能來說可能不是最好的選擇, 但是我們這里是講快速搭建.
再次強調, 上面的代碼必須放在我們的路由之上. 現在你的app.js應該是這樣子的:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
// New Code
var mongo = require('mongodb');
var monk = require('monk');
var db = monk('localhost:27017/nodetest1');
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// Make our db accessible to our router
app.use(function(req,res,next){
req.db = db;
next();
});
app.use('/', routes);
app.use('/users', users);
/// catch 404 and forwarding to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
/// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
接下來我們要修改我們的路由, 這樣我們就能使用數據庫來展現數據了.
STEP 6 – PULL YOUR DATA FROM MONGO AND DISPLAY IT
在編輯器中打開 C:\node\nodetest1\routes\index.js. 現在讓我們來添加一個路由:
/* GET Userlist page. */
router.get('/userlist', function(req, res) {
var db = req.db;
var collection = db.get('usercollection');
collection.find({},{},function(e,docs){
res.render('userlist', {
"userlist" : docs
});
});
});
下一步我們要設置我們的Jade 模版. 導航到C:\node\nodetest1\views\打開index.jade文件. 復制其內容到新建的userlist.jade, 編輯內容如下:
extends layout
block content
h1.
User List
ul
each user, i in userlist
li
a(href="mailto:#{user.email}")= user.username
each中的user代表迭代中的user, i(index)是一個計數器.
保存文件, 重啟node服務:
C:\node\nodetest1>npm start
Now open your browser and head to http://localhost:3000/userlist and marvel in the results.

現在你從數據庫里面取出來數據展現在網頁上了!
PART 4 – 數據庫的寫操作
數據庫的寫操作不難. 記住寫操作一般用 HTTP POST
STEP 1 – 創建數據輸入框CREATE YOUR DATA INPUT
我們先為添加用戶的表單頁面添加一個路由. 打開/routes/index.js 添加下面的代碼(在module.exports前) :
/* GET New User page. */
router.get('/newuser', function(req, res) {
res.render('newuser', { title: 'Add New User' });
});
現在我們添加一個jade模版頁面 newuser.jade:
extends layout
block content
h1= title
form#formAddUser(name="adduser",method="post",action="/adduser")
input#inputUserName(type="text", placeholder="username", name="username")
input#inputUserEmail(type="text", placeholder="useremail", name="useremail")
button#btnSubmit(type="submit") submit
重啟node服務, 打開 http://localhost:3000/newuser 內容如下:

現在點擊submit按鈕會得到一個404錯誤.
STEP 2 – 創建我們的數據功能
現在我們要做的是添加一個Post路由名為 /adduser.
打開 /routes/index.js 添加下面的內容:
/* POST to Add User Service */
router.post('/adduser', function(req, res) {
// Set our internal DB variable
var db = req.db;
// Get our form values. These rely on the "name" attributes
var userName = req.body.username;
var userEmail = req.body.useremail;
// Set our collection
var collection = db.get('usercollection');
// Submit to the DB
collection.insert({
"username" : userName,
"email" : userEmail
}, function (err, doc) {
if (err) {
// If it failed, return error
res.send("There was a problem adding the information to the database.");
}
else {
// If it worked, set the header so the address bar doesn't still say /adduser
res.location("userlist");
// And forward to success page
res.redirect("userlist");
}
});
});
STEP 3 – 連結並且添加一些數據到數據庫
確定mongod是正在運行的! 下面重啟node :
C:\node\nodetest1>npm start
現在我們打開 http://localhost:3000/newuser 添加一些內容(下面的網址不正確請忽略網址).

點擊submit, 我們會跳轉到 /userlist 頁面, 在這個頁面中可以看到我們添加的新用戶!

