在 Express 項目中使用 Waterline
在上一篇Node.js ORM 數據操作中間件 Waterline 中,我們介紹了 Waterline 的功能與特點,這篇文章中我們將用一個實例 waterline-sample (Github、Coding.NET),來看看在 Express 項目中如何使用 Waterline。
要在項目中使用 Waterline ,無非是解決如何配置,在什么時機初始化,怎樣組織所有的數據集合,以及在控制器中怎么調用 Waterline 中的數據集合這幾個問題。
項目的功能與結構
這個示例項目中,將會實現兩個關于 Post 的 API ,添加和獲取列表的接口,功能比較簡單,但代碼的組織,依然遵循模塊化和 MVC 的設計原則,主要的文件和目錄如下:
</span>|-- app | |-- controllers | | `-- post.server.controller.js | |-- models | | `-- post.server.model.js | `-- routes | `-- post.server.routes.js |-- config | |-- config.js | |-- env | | `-- development.js | |-- express.js | `-- waterline.js |-- app.js |-- bin | `-- www `-- package.json
其中,config目錄存儲基本配置、 Express 配置和 Waterline 的配置文件,其中的env目錄存儲根據環境而不同的基本配置。app目錄下的三個文件夾,分別按 MVC 的結構組織 Waterline 的 Collections ,Expresss 的控制器以及路由文件。根目錄下的app.js將使用config/express.js中的配置來生成 Express 的實例,而入口文件bin/www則完成 Waterline 的初始化和啟動 Express 實例的端口監聽。
數據集合的組織
所有的數據集合,全部組織在app/models目錄中,直接使用module.exports來將Waterline.Collections實例導出,以便在 Waterline 的配置文件中調用。
</span>var Waterline = require('waterline');module.exports = Waterline.Collection.extend({ identity: 'post', connection: 'mongo', schema: true, attributes: { title: { type: 'string', required: true }, content: 'string', createTime: 'date', lastModifyTime: 'date' }, beforeCreate: function(v, cb){ v.createTime = new Date(); return cb(); }, print: function(v) { console.log('\tTitle:', v.title, 'create at:', v.createTime); console.log('\tContent:', v.content); } });</pre>
這里也演示了如何定義生命周期回調和自定義的方法。
配置
配置里主要是生成 Waterline 的實例,并加載上面的數據集合配置文件。
</span>var Waterline = require('waterline'); var mongoAdapter = require('sails-mongo'); var config = require('./config');// models var Post = require('../app/models/post.server.model');
var orm = new Waterline(); var wlconfig = { adapters: { 'default': mongoAdapter, mongo: mongoAdapter }, connections: { 'mongo': { adapter: 'mongo', url: config.mongo } } }; orm.loadCollection(Post);
exports.orm = orm; exports.config = wlconfig;</pre>
這里使用的是exports來導出,因為我們有兩個值需要導出,一個是 Waterline 的實例,另外一個是 Waterline 的初始化配置。這在初始化的時候會用到。
初始化
初始化是在bin/www里完成的,原因是保證 Express 啟動監聽,必須在 Waterline 的成功初始化之后進行。
</span>var app = require('../app'); var config = require('../config/config'); var waterline = require('../config/waterline');waterline.orm.initialize(waterline.config, function(err, models){ if(err) { console.log('waterline initialize failed, err:', err); return; } console.log('waterline initialize success.');
app.set('models', models.collections);
app.listen(config.port, function(){ console.log('Express listening on port:', config.port); }); });</pre>
初始化是直接使用 Waterline 實例的intialize()方法,需要傳入對應的配置,這兩個都是在waterline.js配置文件中導出的。為了方便我們在控制器代碼中調用 Waterline 的數據集合,這里先將它加入到 Express 實例的配置列表中。
在 Express 控制器中使用 Waterline 數據集合
由于 Waterline 的初始化過程是異步的,所以我們沒有辦法直接使用module.exports或exports方法來導出它的實例,也就無法直接以 JavaScript 模塊化的方式調用它實例中的數據集合。這里將借助 Express 的實例,來在控制器代碼中使用它。
但實際上,在控制器代碼中,也是沒有辦法直接訪問 Express 的實例的,所以這里我們在 Express 的配置里,增加一個中間件,將附加在 Express 實例上的數據集合,再加入到 Express 請求對象中,這樣便可以在控制器代碼中通過請求對象來訪問 Waterline 實例的數據集合了。當然,加到響應對象也可以。
</span>var express = require('express'); var waterline = require('./waterline');module.exports = function(){ console.log('express initialing...'); var app = express(); // ... app.use(function(req, res, next){ req.models = app.get('models'); next(); });
require('../app/routes/post.server.routes')(app); // ... return app; };</pre>
在控制器里,便可以通過請求對象的models成員來調用了。
module.exports = { list: function(req, res, next){ var page = parseInt(req.query.page, 1) ? parseInt(req.query.page, 1) : 1; var limit = parseInt(req.query.limit, 1) ? parseInt(req.query.limit, 1) : 1; req.models.post.find().paginate({page: page, limit: limit}).exec(function(err, docs){ res.json(docs); }); } };
雖然也可以通過全局變量來調用數據集合,不過在有其它辦法的情況下,還是盡量不要使用全局變量吧。
來自:http://chensd.com/2015-10/Use-Waterline-in-Express-project.html