NodeJS – Lưu trữ dữ liệu với MongoDB


Được đăng vào ngày 10/10/2016 | 0 bình luận
Đánh giá bài viết

Trong phần này chúng ta sẽ tìm hiểu cách lưu trữ dữ liệu trong cơ sở dữ liệu MongoDB

MongoDB

MongoDB là cơ sở dữ liệu dạng NoSQL mã nguồn mở, có khả năng mở rộng và hiệu suất cao, sử dụng cú pháp JSON, không sử dụng khái niệm lược đồ cơ sở dữ liệu… và còn nhiều tính năng khác nữa.

Để cài đặt MongoDB thì bạn tải MongoDB tại địa chỉ: https://www.mongodb.org/downloads

Bạn tải và cài cho đúng với kiến trúc của hệ điều hành của mình (ví dụ máy bạn chạy hệ điều hành 32 bit thì cài bản 32 bit).

Sau khi cài xong thì bạn đưa đường dẫn đến thư mục bin trong thư mục cài đặt MongoDB vào biến môi trường PATH để tiện sử dụng sau này (nếu bạn không biết cách thiết lập biến này thì tham khảo bài trước hoặc tìm trên Google).

Sau đó bạn mở Command Prompt (cmd) lên và chạy lệnh mongod --version để xem phiên bản MongoDB của mình cũng như xác nhận xem đường dẫn đến thư mục bin đã nằm trong biến PATH đúng chưa:

C:\Users\PhoCode>mongod --version
db version v3.2.10
git version: 79d9b3ab5ce20f51c272b4411202710a082d0317
OpenSSL version: OpenSSL 1.0.1t-fips  3 May 2016
allocator: tcmalloc
modules: none
build environemnt:
    distmod: 2008plus-ssl
    distarch: x86_64
    target_arch: x86_64

Phiên bản MongoDB mình dùng ở đây là phiên bản 3.2.10. Mặc định các cơ sở dữ liệu sẽ được lưu trong thư mục C:\data\db trên Windows.

Tạo cơ sở dữ liệu

Chúng ta sẽ tạo một cơ sở dữ liệu trong MongoDB để lưu trữ các ghi chú trong ứng dụng Notes.

Đầu tiên chúng ta mở một Command Prompt lên rồi gõ lệnh mongod để chạy server:

C:\Users\PhoCode>mongod
...

Tiếp theo chúng ta mở một Command Prompt khác lên rồi chạy các lệnh sau:

C:\Users\PhoCode>mongo
MongoDB shell version: 3.2.10
connection to: test
> use notes
switched to db notes

Lệnh mongo sẽ chạy trình shell của MongoDB, trình shell cho phép chúng ta thao tác với server của MongoDB, mặc định trong server có sẵn một cơ sở dữ liệu có tên là test, bất cứ thao tác ghi/đọc nào cũng sẽ được thực hiện trên CSDL này.

Lệnh use <tên CSDL> sẽ tạo một cơ sở dữ liệu với tên tương ứng và thiết lập trình shell chuyển các thao tác đọc/ghi lên CSDL đó, nếu CSDL đó đã có rồi thì chuyển sang sử dụng luôn.

Tạo model

Giống như các phần trước, chúng ta sẽ tạo model chứa các hàm để đọc/ghi dữ liệu.

Trên npm có module mongoose là module dùng để kết nối với cơ sở dữ liệu Mongoose rất mạnh. Đầu tiên chúng ta tạo một thư mục có tên models-mongoose  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 mongoose = require('mongoose');
var Schema = mongoose.Schema;
var dburl = undefined;
exports.connect = function(thedburl, callback) {
    dburl = thedburl;
    mongoose.connect(dburl);
}

exports.disconnect = function(callback) {
    mongoose.disconnect(callback);
}

var NoteSchema = new Schema({
    notekey: String,
    title: String,
    body: String
});

mongoose.model('Note', NoteSchema);
var Note = mongoose.model('Note');

exports.create = function(key, title, body, callback) {
    var newNote = new Note();
    newNote.notekey = key;
    newNote.title = title;
    newNote.body = body;
    newNote.save(function(err) {
        if(err)
            callback(err);
        else
            callback();
    });
}

exports.update = function(key, title, body, callback) { 
    exports.read(key, function(err, doc) {    
        if(err)
            callback(err);
        else { 
            doc.notekey = key;
            doc.title = title;
            doc.body = body;
            doc.save(function(err) {
                if(err)
                    callback(err);
                else
                    callback();
            });
        }
    });
}

exports.read = function(key, callback) {
    Note.findOne({ notekey: key }, function(err, doc) {
        if(err) 
            callback(err);
        else
            callback(null, doc);
    });
}

exports.destroy = function(key, callback) {
    exports.read(key, function(err, doc) {
        if(err)
            callback(err);
        else {
            doc.remove();
            callback();
        }
    });
}

exports.titles = function(callback) {
    Note.find().exec(function(err, docs) {
        if(err)
            callback(err);
        else {
            if(docs) {
                var noteList = [];
                docs.forEach(function(note) {
                    noteList.push({
                    key: note.notekey,
                    title: note.title 
                    }); 
                });
                callback(null, noteList);
            } else { 
                callback();
            }
        }
    });
}

File này cũng giống như các file model khác là chứa các hàm dùng để kết nối, ngắt kết nối, thực hiện các chức năng CRUD.

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var dburl = undefined;
exports.connect = function(thedburl, callback) {
    dburl = thedburl;
    mongoose.connect(dburl);
}

exports.disconnect = function(callback) {
    mongoose.disconnect(callback);
}

Chúng ta sẽ cần đến module mongoose để tương tác với CSDL. Schema là một lớp trong mongoose định nghĩa các trường của một dòng trong một collection. Biến dburl được dùng để lưu đường dẫn kết nối đến CSDL. Hai hàm connect()disconnect() được dùng để kết nối và ngắt kết nối đến CSDL. Để thực hiện kết nối  thì chúng ta dùng hàm mongoose.connect() và truyền vào đường dẫn, ngắt kết nối thì chúng ta gọi hàm mongoose.disconnect() và truyền vào một hàm callback.

var NoteSchema = new Schema({
    notekey: String,
    title: String,
    body: String
});

mongoose.model('Note', NoteSchema);
var Note = mongoose.model('Note');

Chúng ta định nghĩa đối tượng NoteSchema kế thừa từ Schema chứa các trường notekey, title, body tương ứng. Sau đó dùng hàm model() để tạo bảng tương ứng trong CSDL.

exports.create = function(key, title, body, callback) {
    var newNote = new Note();
    newNote.notekey = key;
    newNote.title = title;
    newNote.body = body;
    newNote.save(function(err) {
        if(err)
            callback(err);
        else
            callback();
    });
}

Hàm create() được dùng để tạo các ghi chú, để lưu vào CSDL thì chúng ta gọi hàm save(), hàm này nhận một hàm callback làm tham số.

exports.update = function(key, title, body, callback) { 
    exports.read(key, function(err, doc) {    
        if(err)
            callback(err);
        else {         
            doc.title = title;
            doc.body = body;
            doc.save(function(err) {
                if(err)
                    callback(err);
                else
                    callback();
            });
        }
    });
}

Hàm update() được dùng để cập nhật các ghi chú. Ở đây trước khi cập nhật chúng ta kiểm tra xem ghi chú có tồn tại không bằng cách dùng hàm read() được định nghĩa ở dưới, hàm này nhận vào khóa, nếu không tồn tại thì trả về lỗi, nếu có tồn tại thì chúng ta cập nhật cũng bằng hàm save().

exports.read = function(key, callback) {
    Note.findOne({ notekey: key }, function(err, doc) {
        if(err) 
            callback(err);
        else
            callback(null, doc);
    });
}

Hàm read() được dùng để đọc các ghi chú, hàm này nhận vào khóa key. Hàm findOne() sẽ tìm bản ghi đầu tiên khớp với từ khóa, nếu không tìm thấy thì sẽ báo lỗi, nếu tìm thấy thì dữ liệu tìm được sẽ nằm trong tham số doc trong hàm callback. Nếu bạn muốn tìm toàn bộ thay vì chỉ tìm một bản ghi thì dùng hàm find().

exports.destroy = function(key, callback) {
    exports.read(key, function(err, doc) {
        if(err)
            callback(err);
        else {
            doc.remove();
            callback();
        }
    });
}

Hàm destroy() được dùng để xóa một ghi chú, và cũng tương tự như các hàm trên, hàm này nhận vào khóa key, để xóa một bản ghi trong CSDL thì chúng ta gọi hàm remove().

exports.titles = function(callback) {
    Note.find().exec(function(err, docs) {
        if(err)
            callback(err);
        else {
            if(docs) {
                var noteList = [];
                docs.forEach(function(note) {
                    noteList.push({
                    key: note.notekey,
                    title: note.title 
                    }); 
                });
                callback(null, noteList);
            } else { 
                callback();
            }
        }
    });
}

Hàm titles() sẽ có chức năng tìm toàn bộ ghi chú. Như đã nói ở trên, để lấy toàn bộ bản ghi thì chúng ta gọi hàm find().

Cấu hình project

Chúng ta sửa lại file app.js 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');
models.connect("mongodb://localhost/notes", 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 khai báo module notes trong thư mục models-mongoose. Sau đó để kết nối đến CSDL thì chúng ta gọi hàm connect() đã định nghĩa trong file notes.js ở trên và truyền vào đường dẫn dạng như sau:

mongodb://localhost/notes

Tiếp theo chúng ta khai báo module mongoose 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": "*"
    }
}

Cuối cùng bạn chạy lệnh npm install để cài đặt module.

Bây giờ bạn có thể chạy server để thực hiện các thao tác CRUD như bình thường, và dữ liệu sẽ được lưu trong CSDL MongoDB.

Để kiểm tra, bạn có thể mở lại trình shell của MongoDB và chạy lệnh db.notes.find() như sau:

C:\Users\PhoCode>mongo
MongoDB shell version: 3.2.10
connecting to: test
> use notes
switched to db notes
> db.notes.find()
{ "_id" : ObjectId("57faf19e77a44c30b858315a"), "body" : "Open source is the future", 
"title" : "Phở Code", "notekey" : "phocode", "__v" : 0 }

capture







Trả lời


Lưu ý: bọc code trong cặp thẻ [code language="x"][/code] để highlight code.


Ví dụ:


[code language="cpp"]


    std::cout << "Hello world";


[/code]



Các ngôn ngữ được hỗ trợ gồm: actionscript3, bash, clojure, coldfusion, cpp, csharp, css, delphi, diff, erlang, fsharp, go, groovy, html, java, javafx, javascript, latex, matlab, objc, perl, php, powershell, python, r, ruby, scala, sql, text, vb, xml.

Thư điện tử của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *