Ngoài SQLite ra thì còn có rất nhiều các hệ quản trị cơ sở dữ liệu nổi tiếng và mạnh mẽ, và ứng với mỗi hệ quản trị CSDL thì lại có vài module được dùng để tương tác với CSDL đó từ Node. Trong số đó có một số module cung cấp các hàm ở level cao và cung cấp khả năng sử dụng chỉ một model cho nhiều CSDL khác nhau.
Module Sequelize (http://sequelize.com/) có thể kết nối tới 3 hệ quản trị cơ sở dữ liệu là SQLite3, MySQL và PostgreSQL. Các thao tác với CSDL sẽ được thực hiện theo ORM (Object Relation Mapping).
MySQL
MySQL là một hệ quản trị cơ sở dữ liệu SQL rất mạnh và miễn phí. Nếu bạn đã cài MySQL trong máy rồi thì bạn chỉ cần tạo một CSDL có tên là notes
(không tạo bảng) rồi có thể bỏ qua phần này và kéo xuống phần tạo model phía dưới. Nếu chưa thì bạn lên trang chủ của MySQL và tải bản Community về tại địa chỉ http://dev.mysql.com/downloads/. MySQL là một hệ quản trị cơ sở dữ liệu, phần lõi chịu trách nhiệm lưu trữ, đọc/ghi dữ liệu… tất cả đều được thực hiện qua dòng lệnh, do đó nếu muốn bạn có thể tải thêm phần mềm MySQL Workbench về, đây là phần mềm cho phép bạn làm việc với MySQL thông qua giao diện GUI, nghĩa là thay vì dùng dòng lệnh thì bạn chỉ cần thực hiện các thao tác click chuột đơn giản.
Quá trình cài đặt MySQL rất đơn giản, bạn chỉ cần lưu ý một số thứ như tên tải khoản truy cập, thường là root, mật khẩu, chế độ cài (Developement, Deploy…)…
Sau khi đã cài đặt xong, chúng ta có thẻ bắt đầu truy cập server của MySQL để tạo CSDL. Ở đây mình dùng MySQL Workbench cho nhanh. Khi mở MySQL Workbench lên, bạn sẽ phải tạo những cái gọi là Connections, nếu bạn chưa từng làm việc với Connection thì có thể hình dung đây giống như là các nút để chúng ta thực hiện kết nối tới server vậy. Để tạo một connection thì chúng ta click vào nút dấu + phía trên bên trái màn hình, sau đó điền các thông tin như tên connection, host là 127.0.0.1, port là 3306, username là tên đăng nhập mà bạn tạo khi cài MySQL, vậy là xong.
Sau đó bạn click Ok để tạo, bây giờ bên màn hình sẽ xuất hiện một nút Connection và chúng ta có thể click vào để đăng nhập vào server. Khi đăng nhập thì MySQL Workbench sẽ hỏi password, bạn nhập password lúc cài đặt MySQL là xong.
Tiếp theo chúng ta phải tạo một CSDL để lưu các ghi chú cho ứng dụng Notes. Bạn click vào nút có hình trụ với dấu + để tạo, trong này chúng ta cần cung cấp nên CSDL và collation là tập kí tự, chúng ta sẽ chọn là uttf8_unicode_ci
. Ở đây chúng ta không tạo bảng vì module Sequelize sẽ tự động tạo các bảng đó cho chúng ta. Vậy là quá trình tạo CSDL đã xong, bây giờ chúng ta sẽ tạo mdel.
Tạo model
Chúng ta tạo một thư mục mới có tên models-sequelize
trong thư mục gốc của project, trong thư mục này chúng ta tạo một file có tên notes.js
với nội dung như sau:
var Sequelize = require('sequelize'); var Note = undefined; module.exports.connect = function(params, callback) { var sequlz = new Sequelize( params.dbname, params.username, params.password, params.params ); Note = sequlz.define('Note', { notekey: { type: Sequelize.STRING, primaryKey: true, unique: true }, title: Sequelize.STRING, body: Sequelize.TEXT }); Note.sync().then(function() { callback(); }).error(function(err) { callback(err); }); } exports.disconnect = function(callback) { callback(); } exports.create = function(key, title, body, callback) { Note.create({ notekey: key, title: title, body: body }).then(function(note) { callback(); }).error(function(err) { callback(err); }); } exports.update = function(key, title, body, callback) { Note.find({ where:{ notekey: key} }).then(function(note) { if(!note) { callback(new Error("No note found for key " + key)); } else { note.updateAttributes({ title: title, body: body }).then(function() { callback(); }).error(function(err) { callback(err); }); } }).error(function(err) { callback(err); }); } exports.read = function(key, callback) { Note.find({ where:{ notekey: key} }).then(function(note) { if(!note) { callback("Nothing found for " + key); } else { callback(null, { notekey: note.notekey, title: note.title, body: note.body }); } }); } exports.destroy = function(key, callback) { Note.find({ where:{ notekey: key} }).then(function(note) { note.destroy().then(function() { callback(); }).error(function(err) { callback(err); }); }); } exports.titles = function(callback) { Note.findAll().then(function(notes) { var noteList = []; notes.forEach(function(note) { noteList.push({ key: note.notekey, title: note.title }); }); callback(null, noteList); }); }
Cũng giống như các phần trước, file này sẽ lưu trữ phần model của ứng dụng.
var Sequelize = require('sequelize');
Chúng ta sẽ cần dùng đến module sequelize.
var Note = undefined; module.exports.connect = function(params, callback) { var sequlz = new Sequelize( params.dbname, params.username, params.password, params.params ); Note = sequlz.define('Note', { notekey: { type: Sequelize.STRING, primaryKey: true, unique: true }, title: Sequelize.STRING, body: Sequelize.TEXT }); Note.sync().then(function() { callback(); }).error(function(err) { callback(err); }); } exports.disconnect = function(callback) { callback(); }
Ở đây hàm connect()
không nhận vào một chuỗi thông thường như các phần trước mà sẽ nhận vào một tập các tham số, gồm có tên CSDL (dbname
),
tên đăng nhập (username
),
mật khẩu (password
),
địa chỉ MySQL server và tên loại server (nằm trong tham số params
).
Như đã nói ở trên, chúng ta không tạo bảng một cách trực tiếp mà sequelize sẽ tạo các bảng đó cho chúng ta, bằng cách dùng phương thức define(),
tham số đầu tiên là tên bảng, ở đây mình đặt là Note, sequelize sẽ tạo bảng với tên tương ứng và thêm kí tự s vào sau cùng, tham số thứ hai là một đối tượng chứa các trường tương ứng trong bảng, ở đây bao gồm các trường notekey, title
và body
giống như với các model khác, ngoài ra sequelize sẽ tự động chèn thêm 2 trường nữa là createdAt
và updatedAt
có kiểu dữ liệu datetime để chúng ta có thể biết được các bản ghi được tạo khi nào và được sửa đổi khi nào. Phương thức sync().then()
sẽ thực hiện việc tạo thật sự trên CSDL.
exports.create = function(key, title, body, callback) { Note.create({ notekey: key, title: title, body: body }).then(function(note) { callback(); }).error(function(err) { callback(err); }); }
Hàm create()
sẽ thực hiện tạo các bản ghi mới. Để chèn một bản ghi thì chúng ta chỉ cần gọi phương thức Sequelize.create()
và đưa các tham số tương ứng vào, sau đó gọi hàm then(),
ngoài ra hàm còn có hàm error()
có chức năng kiểm tra xem có lỗi hay không.
exports.update = function(key, title, body, callback) { Note.find({ where:{ notekey: key} }).then(function(note) { if(!note) { callback(new Error("No note found for key " + key)); } else { note.updateAttributes({ title: title, body: body }).then(function() { callback(); }).error(function(err) { callback(err); }); } }).error(function(err) { callback(err); }); }
Hàm update()
sẽ cập nhật các ghi chú. Ở đây thao tác cập nhật hơi khác chút xíu. Đầu tiên chúng ta phải tìm bản ghi đó bằng phương thức find(),
phương thức này nhận vào câu truy vấn, bạn có thể xem cấu trúc truy vấn theo đoạn code trên. Sau đó gọi hàm then(),
hàm này nhận vào một hàm callback và hàm callback này nhận vào dữ liệu trả về. Chúng ta có thể kiểm tra xem dữ liệu trả về này có rỗng hay không, nếu không rỗng thì chúng ta thực hiện cập nhật mới dữ liệu này bằng cách gọi hàm updateAttributes().
exports.read = function(key, callback) { Note.find({ where:{ notekey: key} }).then(function(note) { if(!note) { callback("Nothing found for " + key); } else { callback(null, { notekey: note.notekey, title: note.title, body: note.body }); } }); }
Hàm read()
được dùng để đọc một ghi chú và cũng tương tự như hàm update().
exports.destroy = function(key, callback) { Note.find({ where:{ notekey: key} }).then(function(note) { note.destroy().then(function() { callback(); }).error(function(err) { callback(err); }); }); }
Hàm destroy()
được dùng để xóa một ghi chú, tương tự chúng ta cũng tìm một ghi chú trước rồi nếu thấy thì chúng ta xóa ghi chú đó bằng hàm destroy().
exports.titles = function(callback) { Note.findAll().then(function(notes) { var noteList = []; notes.forEach(function(note) { noteList.push({ key: note.notekey, title: note.title }); }); callback(null, noteList); }); }
Hàm titles()
sẽ liệt kê toàn bộ ghi chú có trong CSDL, để lấy về toàn bộ ghi chú thì chúng ta dùng hàm findAll().
Cấu hình app.js
Trong file app.js
chúng ta sửa lại như sau:
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'); var notes = require('./routes/notes'); //var models = require('./models-fs/notes'); //var models = require('./models-sqlite3/notes'); //var models = require('./models-mongoose/notes'); var models = require('./models-sequelize/notes'); models.connect({ dbname: "notes", username: "root", password: "<mật khẩu>", params: { host: "127.0.0.1", dialect: "mysql" } }, function(err) { if(err) throw err; }); notes.configure(models); routes.configure(models); var app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs'); // uncomment after placing your favicon in /public //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.use('/', routes.index); app.use('/users', users); app.get('/noteadd', notes.add); app.post('/notesave', notes.save); app.use('/noteview', notes.view); app.use('/noteedit', notes.edit); app.use('/notedestroy', notes.destroy); app.post('/notedodestroy', notes.dodestroy); // catch 404 and forward 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;
Ở đây chúng ta lưu ý là tham số để kết nối tới CSDL là một tập các tham số như địa chỉ, username, mật khẩu đăng nhập… bạn điền cho chính xác là được.
Tiếp theo chúng ta khai báo module sequelize
trong file package.json
như sau:
{ "name": "notes", "version": "0.0.0", "private": true, "scripts": { "start": "node ./bin/www" }, "dependencies": { "body-parser": "~1.15.1", "cookie-parser": "~1.4.3", "debug": "~2.2.0", "ejs": "~2.4.1", "express": "~4.13.4", "morgan": "~1.7.0", "serve-favicon": "~2.3.0", "async": "*", "sqlite3": "*", "mongoose": "*", "sequelize": "*" } }
Cuối cùng chúng ta chạy lệnh npm install
để cài module này rồi chạy npm start
để chạy server là xong.
Cứ mỗi lần chạy server, sequelize sẽ tạo mới bảng nếu bảng chưa tồn tại.
C:\NodeJS\notes>npm start > notes@0.0.0 start C:\NodeJS\notes > node ./bin/www notes:server Listening on port 3000 + 0ms Executing (default): CREATE TABLE IF NOT EXISTS 'Notes' ('notekey' VARCHAR(255) UNIQUE , 'title' VARCHAR(255), 'body' TEXT, 'createdAt' DATETIME NOT NULL, 'updatedAt' DATETIME NOT NULL, UNIQUE 'Notes_notekey_unique' ('notekey'), PRIMARY KEY ('notekey')) ENGINE=InnoDB; Executing (default): SHOW INDEX FROM 'Notes'
Bạn có thể vào MySQL Workbench để kiểm tra dữ liệu.