【とりあえずハンズオン】DockerでNoSQLをやってみた

# はじめに

この記事ではデータベースの分野なんて RDS で十分やろ、NoSQL なんてと
思っている一般男性が Docker でちゃちゃっと NoSQL 環境を構築して
どんなもんか試してみる記事です。
ベストプラクティスや間違いがあれば、書き直していく予定です。

## NoSQL とは

Not Only SQL の略
昨今では SQL を利用しないデータベース技術全般を指す。

### 主な特徴

よく言われる特徴としては
非構造化データ、ドキュメント指向、キーバリューストア、列指向といった特徴がある。

### 代表的な OSS など

Redis、memchached、MongoDB...

### AWS では

DynamoDB が NoSQL のサービスに挙げられる。

### RDB とは何が違う

NoSQL では RDB のような関係演算がなく
また、ドキュメント指向データベースにおいてはドキュメントと呼ばれる最小単位でデータを管理し、厳密なスキーマというモノが存在しない。

RDB であれば最小単位はレコードという単位でカラムが定義されており
データのあるなしに関係なくカラムを用意する。

## ハンズオンのセットアップその前に

今回はドキュメント指向のデータベースである MongoDB を利用して NoSQL を体感します。
MongoDB は NoSQL の中でもドキュメント指向データベースに分類されるデータベースです。
まずはドキュメント指向データベースの特徴をおさえていきましょう。

### ドキュメントとは

ドキュメント指向データベースにおける最小単位を表すデータ構造のことをドキュメントといいます。
RDB ではレコードに相当する。

### コレクションとは

ドキュメント指向データベース におけるドキュメントの集合体のことをコレクションといいます。
RDB ではテーブルに相当する。

## ハンズオン

### セットアップ

今回は MogoDB を PC にインストールせず、Docker 環境でセットアップします。
まずは、Docker Hub から mongo イメージを pull

```bash
docker pull mongo
```

```bash

$ docker pull mongo
Using default tag: latest
latest: Pulling from library/mongo
6e0aa5e7af40: Pull complete
d47239a868b3: Pull complete
49cbb10cca85: Pull complete
9729d7ec22de: Pull complete
7b7fd72268d8: Pull complete
5e2934dacaf5: Pull complete
bf9da24d4b2c: Pull complete
d2f8c3715616: Pull complete
e9f96a4a45b0: Pull complete
bd66718f31e2: Pull complete
41ed4d1a1542: Pull complete
7336dfc228e2: Pull complete
Digest: sha256:b66f48968d757262e5c29979e6aa3af944d4ef166314146e1b3a788f0d191ac3
Status: Downloaded newer image for mongo:latest
docker.io/library/mongo:latest

```

※mongodb ではないです。

```bash
docker run --detach -p 8080:8080 --name nosql mongo
docker exec -it nosql sh

```

プロンプトに入ったら

```bash
mongo
```

と打ってインタラクティブモードに入る。

## 基本コマンド

### help

```bash

> help
        db.help()                    help on db methods
        db.mycoll.help()             help on collection methods
        sh.help()                    sharding helpers
        rs.help()                    replica set helpers
        help admin                   administrative help
        help connect                 connecting to a db help
        help keys                    key shortcuts
        help misc                    misc things to know
        help mr                      mapreduce

        show dbs                     show database names
        show collections             show collections in current database
        show users                   show users in current database
        show profile                 show most recent system.profile entries with time >= 1ms
        show logs                    show the accessible logger names
        show log [name]              prints out the last segment of log in memory, 'global' is default
        use <db_name>                set current database
        db.mycoll.find()             list objects in collection mycoll
        db.mycoll.find( { a : 1 } )  list objects in mycoll where a == 1
        it                           result of the last line evaluated; use to further iterate
        DBQuery.shellBatchSize = x   set default number of items to display on shell
        exit                         quit the mongo shell

```

### show dbs

現在、サーバに用意されているデータベースを一覧にして表示する。
local という名前のデータベースはどうやら、MongoDB で予約済みのデータベースとのこと。

```bash
> show dbs

admin   0.000GB
config  0.000GB
local   0.000GB

```

### use

利用するデータベースを選択する。
ここは MariaDB や MySQL などと使い方が似てるので好き。(感想)

```bash

> use ymd
switched to db ymd

```

で、どうやら MongoDB とやらに新規作成コマンドというモノは存在せず
利用するデータベースがなければ勝手に作るとのこと。
（なにそれ怖い）

### show collections

データベース内にあるコレクションをすべて表示する。
コレクションとは RDB でいうところのレコードに相当する。(大事なことなので 2 度)

```bash
> db.ymd.insert({name:"yamada"})
WriteResult({ "nInserted" : 1 })

> show collections
ymd

```

### 射影

同じみ、データの参照には find もしくは findOne を利用する。
findOne は条件に一致したモノを 1 つだけ取り出す。

```bash
> db.ymd.find()
{ "_id" : ObjectId("60798dd00a265a3f171a87a9"), "name" : "yamada" }
> db.ymd.insert({name:"yamada",age:22})
WriteResult({ "nInserted" : 1 })
> db.ymd.insert({name:"yamada",age:27})
WriteResult({ "nInserted" : 1 })
> db.ymd.find()
{ "_id" : ObjectId("60798dd00a265a3f171a87a9"), "name" : "yamada" }
{ "_id" : ObjectId("6079916e0a265a3f171a87aa"), "name" : "yamada", "age" : 22 }
{ "_id" : ObjectId("607991750a265a3f171a87ab"), "name" : "yamada", "age" : 27 }
> db.ymd.findOne({name:"yamada"})
{ "_id" : ObjectId("60798dd00a265a3f171a87a9"), "name" : "yamada" }

```

### 条件つきの射影

SQL でいうところの WHERE に匹敵するもの。
ワイルドカードはダメでした。（もしかして、他に方法があるのかも）

```bash
> db.ymd.find({name:"yamada"})
{ "_id" : ObjectId("60798dd00a265a3f171a87a9"), "name" : "yamada" }
```

### データの更新

データの更新には update を用いる。

```bash
> db.ymd.find()
{ "_id" : ObjectId("60798dd00a265a3f171a87a9"), "name" : "yamada" }
{ "_id" : ObjectId("6079916e0a265a3f171a87aa"), "name" : "yamada", "age" : 22 }
{ "_id" : ObjectId("607991750a265a3f171a87ab"), "name" : "yamada", "age" : 27 }
> db.ymd.update({name:"yamada"},{age:27})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.ymd.find()
{ "_id" : ObjectId("60798dd00a265a3f171a87a9"), "age" : 27 }
{ "_id" : ObjectId("6079916e0a265a3f171a87aa"), "name" : "yamada", "age" : 22 }
{ "_id" : ObjectId("607991750a265a3f171a87ab"), "name" : "yamada", "age" : 27 }

```

name が丸ごと age に置き換わり、yamada が消えましたね。（これ、実務で起きたらアウトな奴や。）

### コレクションの削除

SQL でいうところの DELETE テーブルに匹敵する構文

```bash
> db.ymd.drop()
true

```

消えたのかどうかわからんので確認

```bash
> db.ymd.find()
>
```

消えましたね。

### データベースを削除

dropped Database あんまり使わないだろうけどこれも一応確認

```bash
> db.dropDatabase()
{ "dropped" : "ymd", "ok" : 1 }
```

これってデータベース が 2 つ以上あったときどんな動きするんだ。。。
と思ったら最後に use したモノに対して drop が働くようですね。

```bash
> db
test2
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
test1   0.000GB
>
>
> db.test2.insert({name:"aaa"})
WriteResult({ "nInserted" : 1 })
>
>
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
test1   0.000GB
test2   0.000GB
> db.dropDatabase()
{ "dropped" : "test2", "ok" : 1 }
>
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
test1   0.000GB
>

```

最後に test1 を削除して exit して終了しましょう。

```bash

> use test1
switched to db test1
> db.dropDatabase()
{ "dropped" : "test1", "ok" : 1 }
>
>
>
>
> help
        db.help()                    help on db methods
        db.mycoll.help()             help on collection methods
        sh.help()                    sharding helpers
        rs.help()                    replica set helpers
        help admin                   administrative help
        help connect                 connecting to a db help
        help keys                    key shortcuts
        help misc                    misc things to know
        help mr                      mapreduce

        show dbs                     show database names
        show collections             show collections in current database
        show users                   show users in current database
        show profile                 show most recent system.profile entries with time >= 1ms
        show logs                    show the accessible logger names
        show log [name]              prints out the last segment of log in memory, 'global' is default
        use <db_name>                set current database
        db.mycoll.find()             list objects in collection mycoll
        db.mycoll.find( { a : 1 } )  list objects in mycoll where a == 1
        it                           result of the last line evaluated; use to further iterate
        DBQuery.shellBatchSize = x   set default number of items to display on shell
        exit                         quit the mongo shell
> exit
bye

```

## Docker の終了処理

さらに exit を打って Docker の shell から抜けましょう。
使い終わったコンテナは削除したいのでコマンドをパコパコうちます。

```bash

$ docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED             STATUS             PORTS                               NAMES
39657c4067ed   mongo     "docker-entrypoint.s…"   About an hour ago   Up About an hour   0.0.0.0:8080->8080/tcp, 27017/tcp   nosql

$ docker stop nosql
$ docker ps --all
CONTAINER ID   IMAGE     COMMAND                  CREATED             STATUS                         PORTS     NAMES
39657c4067ed   mongo     "docker-entrypoint.s…"   About an hour ago   Exited (0) 21 seconds ago                nosql
f506e4068511   mongo     "docker-entrypoint.s…"   About an hour ago   Exited (0) About an hour ago             tender_hertz

$ doker rm nosql
$ docker ps --all
CONTAINER ID   IMAGE     COMMAND                  CREATED             STATUS                         PORTS     NAMES
f506e4068511   mongo     "docker-entrypoint.s…"   About an hour ago   Exited (0) About an hour ago             tender_hertz
```

作成に失敗したコンテナもある場合は同じく rm で消しましょう。

## 所感

NoSQL って SQL 使わないだけあってリレーショナルしかやってこなかった人には結構つらいかも。というのも SQL という資産を活用できないところとか今までのデータベースの設計技法などが使えないところとかもうなんだろう、新しく学ぶ感じで違うベクトルの知見が必要なのかなと感じました。

## まとめ

今回は ドキュメント指向データベースのNoSQL、MongoDB をDocker 上で起動してハンズオンしました。
ちなみに、Ruby の Web フレームワークで同じみの Rails に使われているActiveRecordですが、互換インターフェイスを持つ NoSQL として「Mongoid」というものがあるそうです。

とはいえ、個人的には MariaDB か PostgreSQL 安定かな。

## おわり