ドットインストールで作ったチャットサーバの値をMongodbに格納する


## 概要
普段はPHPメインで視野が狭くなりがちなので、切り替えのため[ドットインストールのNode.jsのレッスン](https://dotinstall.com/lessons/basic_nodejs)でチャットサーバを作成しました。
この状態ではJSファイルを再起動すると、データが失われてしまいます。
そのため、MongoDBを使って、チャット内容をDBに格納するようにし、再起動してもデータを引き継ぐようにします。

Node.jsの導入や構文については触れませんので、上記レッスンを基に導入しておいて下さい。

## MongoDBを導入
MongoDBをNode.jsがインストールされたサーバに導入します。
導入は下記手順で行います。

1. mongodb.repoの編集
2. yumインストールを実行
3. MongoDB起動
4. MongoDB Driverインストール

### 1. mongodb.repoの編集

```/etc/yum.repos.d/mongodb.repo
[mongodb]
name=MongoDB Repository
baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64/
gpgcheck=0
enabled=1
```

### 2. yumインストールを実行
```
sudo yum -y install mongodb-org
```

### 3. MongoDBを起動

```
sudo service mongod start
sudo chkconfig mongod on
```

### 4. MongoDB Driverインストール
Node.jsでMongoDBを扱うためドライバをインストールします。
ドライバはMongoDBの公式ドライバのmongodbを使用するか、そのオブジェクトラッパーライブラリのMongooseがあります。
今回はmongodbを利用します。

```
npm install mongodb
```

これでMongoDBの導入は完了です。

## Node.js + MongoDB
プログラム内で導入したドライバを読み込み、MongoDBを操作していきます。

```js:server.js
var MongoClient = require('mongodb');
(中略)

/**
 * MongoDBからデータを取得する
 *
 * @param  {string} id 取得対象のコレクション
 */
var getChatDetail = function (id, callback) {
    MongoClient.connect('mongodb://' + setting.db_host + '/' + setting.db, function(err, db) {
        if (err) {
            return console.dir(err);
        }
        db.collection(setting.collection, function(err, collection) {
            collection.find({}, {chat_data:1, _id : 0}).toArray(function(err, id){
                callback(id);
            });
        });
        db.close();
    });
}

/**
 * MongoDBにデータを格納する
 *
 * @param  {string} id    取得対象のコレクション
 * @param  {array}  posts 格納するチャット内容
 */
function savaChatDetail(id, posts) {
    MongoClient.connect('mongodb://' + setting.db_host + '/' + setting.db, function(err, db) {
        if (err) {
            return console.dir(err);
        }

        var documentName = setting.document;
        var params = {};
        params[documentName] = posts;
        getChatDetail(documentName, function (result) {
            if (result.length !== 0
                && Object.keys(result['0']).length
            ) {
                var updateTarget = {};
                updateTarget[documentName] = result['0'][documentName];
                db.collection(setting.collection, function(err, collection) {
                    collection.updateOne(updateTarget, {$set : params});
                });
            } else {
                // 保険的な意味合いでDBに保存するので失敗しても無視
                db.collection(setting.collection, function(err, collection) {
                    collection.insertOne(params);
                });
            }
            db.close();
        });
    });
}
```

これでMongoDBへのデータ格納と取得の実装が完了しました。
実際にブラウザ上から操作すると下記のようにMongoDB内にデータが登録されました。

```
db.chat.find();
{ "_id" : ObjectId("5a10453d92f6df2653fab4b7"), "chat_data" : [ "pop", "98" ] }
```

これでserver.jsの処理を止めて、再度実行してもデータを引き継ぐことができました。
<img width="784" alt="スクリーンショット 2017-11-20 1.52.56.png" src="https://qiita-image-store.s3.amazonaws.com/0/39671/20d16f41-2b9d-ec00-bd84-13f9139f5241.png">


### Node.jsとMongoDBを使った感想
初めてNode.jsとMongoDBを使って下記の点に躓きました。

* Node.jsはノンブロッキングなため、PHPのように上から処理が流れず、MongoDBからデータを取得してから動くようにするのに苦戦した
* 普段使うMySQLと違ってプライマリーキーがないので、同じ内容のドキュメントが沢山登録されてびっくりした

躓くこともありましたが、普段使ったことがない言語+技術を学習できて良かったです。
今回作ったコードは[こちら](https://github.com/juve534/TIL/tree/master/nodejs/chat_server)に上げました。

最後まで読んで頂きありがとうございました。

## 参考資料
http://mongodb.github.io/node-mongodb-native/2.1/api/
https://qiita.com/itagakishintaro/items/a1519998a91061cbfb1e