Node.jsからMongoDBに接続してみる

「[CentOS7にMongoDBをインストール〜MongoDB起動〜mongoShell起動](https://qiita.com/one-kelvin/items/b1740824da0b3e9af9dd)」に引き続き、Node.jsからMongoDBに接続してみたいと思います。CentOS7がVagrant+VirtualBox上で立ち上がっていて、MongoDBは3.4.10、Node.jsは9.2.0です。
[MongoDB NodeJS Driver](http://mongodb.github.io/node-mongodb-native/)を見ながらやっていきます。


## nodeプロジェクトの準備

`/vagrant`ディレクトリがsynced folderになっているので、その中に`mongolesson`ディレクトリを作ってやっていきます。処理を書いていく`app.js`ファイルも同時に作っておきます。

```
$ cd /vagrant
$ mkdir mongolesson
$ cd mongolesson
$ npm init -y
$ touch app.js
$ ls
app.js package.json
```

準備できました。

## MongoDB NodeJS Driverの導入

とりあえず必要なのはmongodbのドライバーだけなのですが、ESLintも入れておきます

```
$ npm install mongodb esLint
```


## MongoDBに接続する前に

MongoDBサーバーが起動していて、データベースディレクトリが作成されていることが必要です。`mongo`コマンドでシェルが起動すればOKなはずです。

```
$ mongo
MongoDB shell version v3.4.10
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.10
...
```

このときに出てきた`mongodb://127.0.0.1:27017`をメモしておきます。

## MongoDBに接続する

MongoDBに接続するjsファイルを書きます。ほぼドキュメント通りです。
`MongoClient.connect(url, [option], [callback])`の第1引数に渡すURLですが、mongoシェルを起動したときにメモしたものにデータベースの名前をつなげたものです。データベース自体は作成していなくても問題ありません。また、初期設定だと127.0.0.1がlocalhostに割り当てられていると思うので、URLを`mongodb://localhost:27017/myDB`としてもOKです。
`assert`モジュールは通常ユニットテストを書くときに使うものですが、`err`が発生していないことの確認に使っています。

```app.js
const mongodb = require('mongodb')
const MongoClient = mongodb.MongoClient
const assert = require('assert')

MongoClient.connect('mongodb://127.0.0.1:27017/myDB', (err, db) => {
    assert.equal(null, err)
    console.log("Connected successfully to server")
    db.close()
})
```

実行してみます。

```
$ node app.js
Connected successfully to server
```

このようになれば成功です。

# insertしてみる

`app.js`にinsertを行う関数を追加します。

```app.js
const mongodb = require('mongodb')
const MongoClient = mongodb.MongoClient
const assert = require('assert')

MongoClient.connect('mongodb://localhost:27017/myDB', (err, db) => {
    assert.equal(null, err)
    console.log("Connected successfully to server")
    insertDocuments(db, () => {
        db.close()
    })
})

const insertDocuments = (db, callback) => {
    const documents = [
        { a: 1 },
        { a: 2 },
        { a: 3 }
    ]
    // myDBデータベースのdocumentsコレクションに対して
    // ドキュメントを3つ追加します
    db.collection('documents').insertMany(documents, (err, result) => {
        // insert結果の確認
        assert.equal(err, null)
        assert.equal(3, result.result.n)
        assert.equal(3, result.ops.length)

        console.log("Inserted 3 documents into the collection")
        callback(result)
    })
}
```

実行してみます。

```
$ node app.js
Connected successfully to server
Inserted 3 documents into the collection
```

成功したようなのでmongoシェルでも確認してみます。

```
$ mongo
...

> use myDB
switched to db myDB
> show collections
documents
> db.documents.find()
{ "_id" : ObjectId("5a13aa733c67677b0a26437b"), "a" : 1 }
{ "_id" : ObjectId("5a13aa733c67677b0a26437c"), "a" : 2 }
{ "_id" : ObjectId("5a13aa733c67677b0a26437d"), "a" : 3 }
```

myDBデータベースは作成していませんが、自動で作成されています。また、documentsコレクションも作成され、3つのドキュメントが追加されています。


# ES6でのMongoDBへの接続

[Quick Start](http://mongodb.github.io/node-mongodb-native/2.2/quick-start/quick-start/)ではこの`MongoClient.connect()`の中でMongoDBに接続し、insertなどの処理を呼び出しています。これはこれで良いのですが、`MongoClient.connect()`がPromiseを返すことを利用することもできます。[MongoClient](http://mongodb.github.io/node-mongodb-native/2.2/api/MongoClient.html)
ドキュメントでは以下のような[co](https://www.npmjs.com/package/co)を利用したコードになっています。

```app_es6.js
const mongodb = require('mongodb')
const MongoClient = mongodb.MongoClient
const co = require('co')
const assert = require('assert')

co(function* () {
    const db = yield MongoClient.connect('mongodb://localhost:27017/myDB')
    console.log("Connected successfully to server")
    db.close()
}).catch(err => {
    console.log(err.stack);
})
```

実行してみると

```
$ node app.js
Connected successfully to server
```

いけます。nodeのバージョンが古いとエラーが出るということもあるかもしれません。これでもいけるのですが、coの使い方というかGeneratorがよくわかっていないので、普通にthenやcatchでつなげた書き方にしてみたいと思います。

```app_es6.js
const mongodb = require('mongodb')
const MongoClient = mongodb.MongoClient

MongoClient.connect('mongodb://localhost:27017/myDB').then(db => {
	console.log("Connected successfully to server")
   	db.close()
}).catch(err => {
    console.log(err)
})
```

```
$ node app.js
Connected successfully to server
```

いけます。insertもやってみます。

```js
const mongodb = require('mongodb')
const MongoClient = mongodb.MongoClient
const assert = require('assert')

MongoClient.connect('mongodb://localhost:27017/myDB').then(db => {
    db.collection('documents').insertMany([
        { b: 1 },
        { b: 2 },
        { b: 3 }
    ], (err, result) => {
        assert.equal(err, null)
        assert.equal(3, result.result.n)
        assert.equal(3, result.ops.length)
        console.log("Inserted 3 documents into the collection")
    })
    db.close()
}).catch(err => {
    console.log(err)
})
```

```
$ node app_es6.js 
Inserted 3 documents into the collection
$ mongo
...

> use myDB
> db.documents.find()
{ "_id" : ObjectId("5a13aa733c67677b0a26437b"), "a" : 1 }
{ "_id" : ObjectId("5a13aa733c67677b0a26437c"), "a" : 2 }
{ "_id" : ObjectId("5a13aa733c67677b0a26437d"), "a" : 3 }
{ "_id" : ObjectId("5a13b378f8ce107b7021881e"), "b" : 1 }
{ "_id" : ObjectId("5a13b378f8ce107b7021881f"), "b" : 2 }
{ "_id" : ObjectId("5a13b378f8ce107b70218820"), "b" : 3 }
```

入りました。Promiseを使った書き方もできますね。次は実際にアプリケーションに組込んでみたいと思います。