データをDBに配置する-Express MongoDB を使って簡単なアプリを作る



## 前回の記事
[データをサーバー側に配置する-Express MongoDB を使って簡単なアプリを作る](https://atoris1192.qrunch.io/entries/4FDCIoLSoxiPyfQc)
前回の記事で、データをサーバー側に配置しましたが、今回はデータベースにデータを入れて運用したいと思います。

### 最終の記事はQruchにupしましたので、よろしければ寄ってください。
[herokuに登録する-Express MongoDB を使って簡単なアプリを作る](https://atoris1192.qrunch.io/entries/trP2v8b4KabkhKKa)


### 使用ライブラリのバージョン


| パッケージ | バージョン |
| --- | --- |
| MongoDB | v4.0.4 |

インストールが済んでいれば、`sudo mongod` で`Mongo`サーバーがdefult状態で起動しますので、`MongoShell`で中に入れることを確認します。

```sh
mongo
> show dbs
admin      0.000GB
config     0.000GB
local      0.000GB
>exit
```
MongoDB側は、OKですので　`node.js`からアクセスできるように、ドライバーをインストールしていきます。

---

`yarn add mongodb` でドライバーをインストールします。

`package.json ` を確認します。

```json
{
  "name": "myapp",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "cookie-parser": "~1.4.3",
    "debug": "~2.6.9",
    "express": "~4.16.0",
    "http-errors": "~1.6.2",
    "mongodb": "^3.1.10",
    "morgan": "~1.9.0",
    "node-sass-middleware": "0.11.0",
    "pug": "2.0.0-beta11"
  }
}
```

ドライバーが入ったので、`index.js`に設定を追加していきます。


```js
var express = require('express');
var router = express.Router();
const MongoClient = require('mongodb').MongoClient
const url = 'mongodb://localhost:27017/myproject'
const dbName = 'myproject'

const main = async () => {
  const client = new MongoClient(url, { useNewUrlParser: true })
  await client.connect()
  console.info("Connected  Server ...")
  const db = client.db(dbName)
  /* GET home page. */
  router.get('/', function(req, res, next) {
    res.render('index', { title: 'Express' });
  });
  router.get('/api/insertMany', async(req, res, next) => {
    const collection = db.collection('omikuji')
    await collection.insertMany([
      {"item": "大吉"},
      {"item": "中吉"},
      {"item": "末吉"},
      {"item": "凶"},
    ])
      .then(r => console.log(r.result))
      .catch(err => console.error(err))
    res.send('insertMany done')
  })
  router.get('/api/random', async(req, res, next) => {
    const collection = db.collection('omikuji')
    const result = await collection.aggregate([
      { $sample: { size: 1 }}
    ]).toArray()
    // console.log(result[0])
    res.json(result[0])
  })
  // router.get('/api/random', (req, res, next) => {
  //   const items = [ '大吉', '中吉', '末吉', '凶']
  //   const random = Math.floor(Math.random()*items.length)
  //   const item = {
  //     item: items[random]
  //   }
  //   res.json(item)
  // })
}
main()

module.exports = router;
```

だいぶ賑やかになりましたが、DBには基本コレクションメソッドを使ってアクセスしますので、それの準備の記述だと思ってもらったらいいかと思います。
コレクションメソッドの基本は`collection.find`, `collection.delte`, `collection.update` などの形にして使いたいのです。

コレクションというのは、エクセルソフトのシートによく例えられますがコードを書いている人であれば、`javascript`で`DOM`を操作するところを例にしたほうがわかりやすいかもしれません。

`const btn = document.querySelector('#btn')` この記述でクリックしたり、結果表示を書き込んだり出来るようになりますが、コレクションメソッドも`collection`を元に切ったり張ったりする感じです。

あと、DBとExpressサーバーは、別物なのでデータの取得には、コスト（時間）がかかると考えます。そのため`await`を挟んで処理結果がやってくるのを待つ必要があります。　いわゆる非同期処理というものです。　`await` を使いたい場合は、`async` もセットで使う必要があります。

実装すると、だいたい上記のようなコードに収まります。

DBには、まだデータがはいっていませんので、`/api/insertMany` を使っていれてみます。　ブラウザーのURL欄を使えばいいですね。

`http://localhost:3000/api/insertMany`を実行すると`insertMany done` と表示が出るはずですので、DBにデータが入ったはずです。
`mongo Shell`を使って実際確認してみるといいかもしれません。

`/api/random` を実行すると、値がランダムに一個取得されます。
こちらもブラウザーのURLで確認してみます。


<img width="423" alt="27-2-1.png" src="https://qiita-image-store.s3.amazonaws.com/0/131175/346250bf-7838-b7e2-7343-2d50c3503fe4.png">


---
`index.js` 抜粋

```js
const result = await collection.aggregate([
  { $sample: { size: 1 }}
]).toArray()

```
コレクションメソッドの中身を簡単に説明しますと`aggregate`は、主に集計時に使うメソッドなのですが、そのときのオプションに、ランダムな値を取得する`$sample`が用意されていますので、これを使ってランダムな値(MongoDB的には、ドキュメント)を取得しています。

まさに今回ほしい命令で、JSで乱数を作る必要もなくなります。
返り値は、配列ですので結果の0番目を取得しています。

`http://localhost:3000/`にアクセスして、運勢が占えるか確認してみてください。

---

### 削除と追加

これでほぼ実装は完了したのですが、せっかくなので全削除と１件追加も実装してみたいと思います。

`index.js`

```js
var express = require('express');
var router = express.Router();
const MongoClient = require('mongodb').MongoClient
const url = 'mongodb://localhost:27017/myproject'
const dbName = 'myproject'

const main = async () => {
  const client = new MongoClient(url, { useNewUrlParser: true })
  await client.connect()
  console.info("Connected  Server ...")
  const db = client.db(dbName)
  /* GET home page. */
  router.get('/', function(req, res, next) {
    res.render('index', { title: 'Express' });
  });

  // api
  router.post('/api/new', async(req, res) => {
    const collection = db.collection('omikuji')
    console.log(req.body)
    await collection.insertOne(req.body)
      .then(r => console.log(r.result))
      .catch(err => console.error(err))

    res.redirect('/')
  })
  router.get('/api/deleteMany', async(req, res) => {
    const collection = db.collection('omikuji')
    await collection.deleteMany({})
      .then(r => console.log(r.result))
      .catch(err => console.error(err))
    res.send('DeleteMany done')
  })
  router.get('/api/insertMany', async(req, res, next) => {
    const collection = db.collection('omikuji')
    await collection.insertMany([
      {"item": "大吉"},
      {"item": "中吉"},
      {"item": "末吉"},
      {"item": "凶"},
    ])
      .then(r => console.log(r.result))
      .catch(err => console.error(err))
    res.send('insertMany done')
  })
  router.get('/api/random', async(req, res, next) => {
    const collection = db.collection('omikuji')
    const result = await collection.aggregate([
      { $sample: { size: 1 }}
    ]).toArray()
    // console.log(result[0])
    res.json(result[0])
  })
}
main()

module.exports = router;

```

`/api/delteMany` はブラウザーのURL欄を使えば、DBからデータをすべて削除してくれるはずです。

`/api/new` は、１件追加用なのですが、`post`命令を使っているので、残念ながらブラウザーのURL欄が使えませんので、`curl`, `HTTPie`などのターミナルから使える、httpクライアントを使います。

今回は、`HTTPie`をつかいますので、入ってない場合は便利なので入れてみてください。

`http localhost:3000/api/random`

```sh
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 53
Content-Type: application/json; charset=utf-8
Date: Thu, 27 Dec 2018 02:16:05 GMT
ETag: W/"35-qdu8Y7FAKzal0TPpKO3d/AM4Y0c"
X-Powered-By: Express

{
    "_id": "5c2228cd2b7dc207d918d875",
    "item": "のの吉"
}
```

`http localhost:3000/api/deleteMany` データを消しておきます

`http POST localhost:3000/api/new item=momo` データを１件入れます

`http localhost:3000/api/random` １件しか入っていないはずなので、`momo`のデータが取得できるはずです。

サーバー側の実装は終わりましたので、フロントエンド側に１件のデータを投げる部分を記述していきたいと思います。

---



`index.pug`にポスト用フォームを追加します。

```pug
extends layout

block content
  #btn 今日の運勢
  section.new
    form(method="POST" action="/api/new")
      input(type="text" name="item" placeholder="ネコ吉" ).item
      input(type="submit" value="Create").submit
  script(src="javascripts/main.js")

```

スタイルもつけておきます

`style.scss`

```css
#btn {
  margin: 60px auto 0;
  width: 300px;
  height: 100px;
  border-radius: 5px;
  background-color: #ec3f3f;
  color: #fff;
  text-align: center;
  line-height: 100px;
  font-size: 33px;
  font-weight: bold;
  cursor: pointer;
  opacity: .8;
  user-select: none;
  &:hover {
    opacity: 1;
  }
}
.new {
  margin: 20px auto 0;
  width: 300px;
  height: 50px;
  line-height: 50px;
  background-color: rgba(40, 46, 40, 0.507);
  color: #fff;
  text-align: center;
  border-radius: 5px;
  .submit{
    width: 80px;
    color: red;
    cursor: pointer;
    font-size: 24px;
    margin: 0 10px;
  }
}

```


<img width="423" alt="27-2-2.png" src="https://qiita-image-store.s3.amazonaws.com/0/131175/651069ba-3191-2138-cbb9-e1baccb50b74.png">


いい感じに、収まったのではないでしょうか。(笑)

`http://localhost:3000/`にアクセスして、追加と占が出来るか試してみてください。


今回はここまでにしたいと思います。
次回で終了にするつもりですが、内容的には`csrf`対策を最低限施して、`heroku` にサービスとしてupしたいと思います。

`Qiita`と`Qranch` にクロス投稿をしていましたが、最後の記事は、`Qranch`のみにしますので、良ければよっていってください。　よろしくおねがいします。`m(__)m`


[herokuに登録する-Express MongoDB を使って簡単なアプリを作る](https://atoris1192.qrunch.io/entries/trP2v8b4KabkhKKa)

## ここまでのコード
コミット: step3.1

コードは、`github`にもupしていますので、うまく動かない方は覗いてみてください。`https://github.com/atoris1192/omikujiExpress2`

```sh
git reset --hard e87b2fc88c47
git pull origin master
git reset --hard 7f13d73fd0014
```