前回の【node.js】socket.ioを使って簡単にチャットを作る方法の続きです。今回はチャットした内容をデータベースに保存する方法です。こうすることによって、一回ブラウザを閉じて再度開いた時に閉じる前のメッセージが残っていたり、途中から参加した人も今までのメッセージが読めるようになります。いくら保存できるようになったとしても、製品レベルには程遠く、脆弱性対策もしていないので、今回は、node.jsでMongoDBを使うことと、MongoDB のオブジェクトモデリングツールであるMongoose(マングース)の使い方のポイントだけを抑えて頂ければと思います。

今回のポイント

  • Mongooseをインストールして簡単な使い方。
  • チャットのメッセージを保存する。
  • ブラウザを閉じてもメッセージが残っている。
  • メッセージを削除する。
  • 削除したメッセージは、相手にも削除されるようにする。

※予めMongoDBが使える状態にしててください。

必要なnode_modules

  • ejs
  • express
  • mongoose
  • socket.io

Mongooseのインストール

インストールはいつものnpmでめっちゃ簡単にインストールできます。

$ npm install mongoose

npm http GET https://registry.npmjs.org/mongoose
npm http 200 https://registry.npmjs.org/mongoose
npm http GET https://registry.npmjs.org/mongoose/-/mongoose-3.0.2.tgz
npm http 200 https://registry.npmjs.org/mongoose/-/mongoose-3.0.2.tgz
npm http GET https://registry.npmjs.org/mongodb/1.1.4
npm http GET https://registry.npmjs.org/ms/0.1.0
npm http GET https://registry.npmjs.org/hooks/0.2.1
npm http 200 https://registry.npmjs.org/ms/0.1.0
npm http GET https://registry.npmjs.org/ms/-/ms-0.1.0.tgz
npm http 200 https://registry.npmjs.org/hooks/0.2.1
npm http GET https://registry.npmjs.org/hooks/-/hooks-0.2.1.tgz
npm http 200 https://registry.npmjs.org/mongodb/1.1.4
npm http GET https://registry.npmjs.org/mongodb/-/mongodb-1.1.4.tgz
npm http 200 https://registry.npmjs.org/ms/-/ms-0.1.0.tgz
npm http 200 https://registry.npmjs.org/hooks/-/hooks-0.2.1.tgz
npm http 200 https://registry.npmjs.org/mongodb/-/mongodb-1.1.4.tgz
npm http GET https://registry.npmjs.org/bson/0.1.1
npm http 200 https://registry.npmjs.org/bson/0.1.1
npm http GET https://registry.npmjs.org/bson/-/bson-0.1.1.tgz
npm http 200 https://registry.npmjs.org/bson/-/bson-0.1.1.tgz
npm WARN package.json bson@0.1.1 No README.md file found!

> bson@0.1.1 install /node_modules/mongoose/node_modules/mongodb/node_modules/bson
> node install.js

================================================================================
=                                                                              =
=  To install with C++ bson parser do <npm install mongodb --mongodb:native>   =
=                                                                              =
================================================================================
mongoose@3.0.2 node_modules/mongoose
├── hooks@0.2.1
├── ms@0.1.0
└── mongodb@1.1.4 (bson@0.1.1)

app.jsを編集

前回の【node.js】socket.ioを使って簡単にチャットを作る方法のソースからMongooseの追記だけをしたサンプルです。


/**
 * Module dependencies.
 */

var express = require('express')
  , routes = require('./routes')
  , mongoose = require('mongoose');

var app = module.exports = express.createServer();

// Configuration
app.configure(function(){
  app.set('views', __dirname + '/views');
  app.set('view engine', 'ejs');
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(express.cookieParser());
  app.use(express.session({ secret: 'your secret here' }));
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

app.configure('development', function(){
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
  app.use(express.errorHandler());
});

// Routes
app.get('/', routes.index);
app.listen(3000, function(){
  console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
});

//mongoose
var Schema = mongoose.Schema;
var UserSchema = new Schema({
  message: String,
  date: Date
});
mongoose.model('User', UserSchema);
mongoose.connect('mongodb://localhost/chat_app');
var User = mongoose.model('User');

//socket
var io = require('socket.io').listen(app);
io.sockets.on('connection', function (socket) {
  socket.on('msg update', function(){
    //接続したらDBのメッセージを表示
    User.find(function(err, docs){
      socket.emit('msg open', docs);
    });
  });

  console.log('connected');

  socket.on('msg send', function (msg) {
    socket.emit('msg push', msg);
    socket.broadcast.emit('msg push', msg);
    //DBに登録
    var user = new User();
    user.message  = msg;
    user.date = new Date();
    user.save(function(err) {
      if (err) { console.log(err); }
    });
  });

  //DBにあるメッセージを削除
  socket.on('deleteDB', function(){
    socket.emit('db drop');
    socket.broadcast.emit('db drop');
    User.find().remove();
  });

  socket.on('disconnect', function() {
    console.log('disconnected');
  });
});

chat.jsを編集

// Client
$(function() {

  var socket = io.connect('http://localhost');

  socket.on('connect', function() {
    socket.emit('msg update');
  });

  $('#btn').click(function() {
    var message = $('#message');
    socket.emit('msg send', message.val());
  });

  $('#delete').click(function(){
    socket.emit('deleteDB');
  });

  socket.on('msg push', function (msg) {
    var date = new Date();
    $('#list').prepend($('<dt>' + date + '</dt><dd>' + msg + '</dd>'));
  });


  //接続されたらDBにあるメッセージを表示
  socket.on('msg open', function(msg){
    //DBが空っぽだったら
    if(msg.length == 0){
        return;
    } else {
      $('#list').empty();
      $.each(msg, function(key, value){
        $('#list').prepend($('<dt>' + value.date + '</dt><dd>' + value.message + '</dd>'));
      });   
    }
  });

  //DBにあるメッセージを削除したので表示も消す
  socket.on('db drop', function(){
    $('#list').empty();
  });

});

ターミナルでMongoDBを起動します。

$ mongod

app.jsを起動します。

$ node app.js

上手く起動すれば、http://localhost:3000でアクセスできると思います。

解説します。

さて、ここでのポイントは、送られてきたメッセージをMongoDBに登録する作業です。はじめに、

mongoose = require('mongoose');
でMongooseをrequireします。

次はMongooseの初期設定です。MongoDBに保存するデータ型を設定します。今回は簡単なチャットなので、メッセージのString型と、日付のDate型だけ登録しておきます。

//mongoose
var UserSchema = new Schema({
  message: String, //チャットのメッセージ
  date: Date //メッセージの送受信時間
});

connectでMongoDBと接続しますが、今回もローカルなのでlocalhost、次はデータベース名です。「chat_app」としました。

mongoose.connect('mongodb://localhost/chat_app');

socket.ioが接続されたら、まずはMongoDBの中に既にメッセージがあるかチェックします。

User.find(function(err, docs){ //メッセージを探す。
  socket.emit('msg open', docs); //返って来た値をemitする。
});

emitでchat.jsの方に命令が行きます。引数にメッセージの中身が入っているので、chat.jsで表示させてあげる記述をします。chat.jsを見て下さい。

//chat.js
 //接続されたらDBにあるメッセージを表示
  socket.on('msg open', function(msg){
    //DBが空っぽだったら
    if(msg.length == 0){
        return;
    } else {
      $('#list').empty();
      $.each(msg, function(key, value){
        $('#list').prepend($('<dt>' + value.date + '</dt><dd>' + value.message + '</dd>'));
      });   
    }
  });

ここのところですね。引数msgが空っぽならretuneで返して、入っていたらjQueryのeachでタグにして表示させる記述です。最初にempty()してあるのは、途中で誰かが入ってきたら実行されてしまうので、重複した内容が表示されるのを防ぐために、empty()して空にすることにしました。もう少しスマートなやり方がありそうですね・・・。次はメッセージを送った時の処理です。

//app.js
socket.on('msg send', function (msg) {
  socket.emit('msg push', msg); //自分へemit。
  socket.broadcast.emit('msg push', msg); //broadcastで相手側。
  //DBに登録
  var user = new User();
  user.message  = msg; //メッセージを代入。
  user.date = new Date(); //時間を記録。
  user.save(function(err) { //saveでMongoDBに登録。
    if (err) { console.log(err); }
  });
});

たったこれだけです。とても簡単ですね!次はMongoDBの内容を削除して、チャットの内容も削除する方法です。削除のボタンを押した時のイベントを設定します。

//chat.js
$('#delete').click(function(){
  socket.emit('deleteDB'); //emitしてapp.jsに伝えます。
});
//app.js
//DBにあるメッセージを削除
socket.on('deleteDB', function(){
  socket.emit('db drop'); //表示を消すためにchat.jsに伝えます。
  socket.broadcast.emit('db drop'); //broadcastで開いてる全員に伝えます。
  User.find().remove(); //データベースを削除します。
});
//chat.js
//DBにあるメッセージを削除したので表示も消す
socket.on('db drop', function(){
  $('#list').empty(); //表示を消す。
});

今回は一気に全部のメッセージを消しましたが、もちろん個別に消すこともできますし、投稿した本人しか消せないようにすることもできます。

まとめ

MongoDBを使うとWEBアプリの表現の幅が一気に広がります。MongoDBはnode.jsと親和性が高いので、Mongooseを使って簡単にデータベースの操作ができます。チャットとしては完成度が低く、脆弱性対策もしていないので、このサンプルコードをそのまま公開するのは避けましょう。あくまでも、node.jsの可能性と、Mongooseの使い方だけを紹介だけなので、その辺はあしからず。

【Node.js】Socket.IO+MongoDBを使って保存できるチャットを作る方法
Pocket

Tagged on:             

2 thoughts on “【Node.js】Socket.IO+MongoDBを使って保存できるチャットを作る方法

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です