MongoDBを使って分かったことのメモ

# はじめに
　MongoDBを使う機会がありましたが、日本語の記事が少なく導入に苦労しました。自分個人の備忘のためにまとめとして書きますが、これからMongoDBを利用しようと考えている方の参考になればと思います。
　また、Qiitaへの投稿が初めてですので、至らぬ点があるかと思います。コメント等でご指摘頂ければ有り難いです。

# Mongoの概要
## MongoDBとは
　MongoDBはドキュメント指向データベースです。DB-Enginesでは2017年12月時点で第5位となっています。>https://db-engines.com/en/
　現在3.4ですが、公式のマニュアルがこちらです。>https://docs.mongodb.com/manual/

## 所感
　RDBMSのようにスキーマを持たないので軽快で、NoSQLよりも集計（CountやGroupに似たこと）が得意です。MongoDBはRDBMSとNoSQLの良いところを取ろうとしている印象を受けます。もちろん各DBによって得意不得意があるので、要件や仕様によって使い分けは必要です。
　RDBMSよりはガンガンinsert出来て、NoSQLよりは部分一致検索や件数カウントが強いです。ログやアンケート回答など、トランザクションが不要で集計が必要なシステムにはMongoDBが適していると考えています。

## 具体的な用語
__コレクション__
　RDBMSで言うテーブルです。後述するドキュメントの集合を管理するものです。スキーマレスなのでテーブル定義が不要です。create文とかは不要で、insertすると勝手に作られます。

__ドキュメント__
　RDBMSで言うレコードです。スキーマレスなので、１つのコレクションの中に構造の異なるドキュメントが存在することも可能です。insertなんかはNoSQLそのままで、_idをキーにバリューが格納されるイメージです。_idは指定することも可能ですが、勝手に一意のキーが振られます。

__フィールド__
　RDBMSで言うカラムです。列と言った方が分かりやすいでしょうか。ただし、フィールドの中に配列やフィールドが存在することもあります。スキーマレスなNoSQLなので当然ですね。

__レプリケーション__
　レプリカセット（Replica Set）とも言います。DBの冗長化構成で出てきます。所謂ミラーリングのことで、Mongoの設定ファイルで指定できます。

__シャーディング__
　こちらはデータ分散です。RAID0とか言うと分かりやすいでしょうか。こちらもMongoの設定ファイルで指定できます。

# 導入
## CentOS7にインストール
　私はさくらVPSを借りているのですが、そこで行ったCentOS7への導入手順を記します。導入手順については公式を参考にしています。 >https://docs.mongodb.com/manual/tutorial/install-mongodb-on-red-hat/

今回はMongoDB3.4を入れます。まずはyumリポジトリに追加します。
`# /etc/yum.repos.d/mongodb-org-3.4.repo`

```
[mongodb-org-3.4]
  name=MongoDB Repository
  baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.4/x86_64/
  gpgcheck=1
  enabled=1
  gpgkey=https://www.mongodb.org/static/pgp/server-3.4.asc
```

次にyumでインストールし、起動します。
`# yum install -y mongodb-org`
`# systemctl start mongod`

起動したらmongoで早速使えます。
`# mongo`

## 認証設定
　上記の初期設定だとlocalhostからしかアクセス出来ませんが、認証無しでアクセス出来ます。認証設定も公式を参考にします。 >https://docs.mongodb.com/manual/tutorial/enable-authentication/

まずはユーザを作成します。userとpwdは適宜変更してください。

```
use admin
db.createUser(
  {
    user: "myUserAdmin",
    pwd: "abc123",
    roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
  }
)
```

次にconfを変更します。初期設定ではsecurityがコメントアウトされているので、コメントアウトを外し、authorizationを有効にします。
`# vi /etc/mongod.conf`

```
security:
  authorization: enabled
```

これでmongodを再起動し、認証なしでアクセス出来ないことを確認します。IPアドレス制限をかける場合はbindIpで指定します。

```
bindIp: 127.0.0.1
```

再度Mongoを再起動し、ログイン出来るか確認します。
`# systemctl start mongod`
`# mongo admin -u myUserAdmin -p`

## マネージドサービスの利用
__MongoDB Atlas__
　CentOSでオンプレ構築する方法を記載しましたが、個人で触ってみる程度であればSaaSが良いと思います。オンプレ環境でトラブルシューティングをすると技術的知識も深まりますが、ほとんどの人はMongoの使い方を覚えるのでお腹一杯になるはずです。
　ということで、MongoDB Atlasを紹介します。無料会員登録が必要ですが、登録すればフリープランでMongoサーバを１台使うことができます。触ってみるには十分な環境なのでお勧めです。>https://www.mongodb.com/cloud

## クライアントツール
__Robo 3T__
　MongoDBを使うと中身をGUIで見たいと思うはずです。Mongoに限りませんが、GUIで中身が見えると取っ掛かり易くなるかなと思います。
　Mongo用のクライアントツールは多々ありますが、私はRobo 3Tを利用しています。使い方自体は単純ですが、接続の認証が若干分かり辛いかもしれません。 >https://robomongo.org/

# 基本操作
　次にコンソールからの基本的なコマンドメモです。上から順にDB一覧表示、DB切り替え、テーブル一覧表示です。
`> show dbs`
`> use admin`
`> show collections`
　基本的なCRUD操作を例に挙げますが、その他様々なメソッドが用意されています。>https://docs.mongodb.com/v3.4/reference/method/js-collection/

## Create
　続いてドキュメント（レコード）を作成する手順です。>https://docs.mongodb.com/v3.4/reference/method/db.collection.insert/
　Mongoはスキーマレスなのでコレクション（テーブル）を予め作成する必要がありません。これはDBも同じで、DBを予め作成していなくても、insert時に勝手に作成されます。
　今回はhogeというDBにtestというコレクションにドキュメントを１つ作成してみました。ドキュメント自体はjson形式で入れます。json形式ならデータの型等を気にせず作成出来るところがMongoDBです。

```
use hoge
db.test.insert(
  {
    name: "mogamoga",
    age: 80,
    groups: [
      {
        title: "group1",
        description: "hogehoge",
      },
      {
        title: "group2",
      },
    ],
  }
)
```

## Read
　続いてドキュメントを取得する手順です。単純な取得ならfindで簡単です。>https://docs.mongodb.com/v3.4/reference/method/db.collection.find/

```
db.test.find({})
```

　これで全件取得出来ます。SELECT * FROM test;みたいな感じです。勿論json形式で返って来ます。以下は先ほどのコマンドの出力結果です。
`{ "_id" : ObjectId("5a27da255b22277a949b2cab"), "name" : "mogamoga", "age" : 80, "groups" : [ { "title" : "group1", "description" : "hogehoge" }, { "title" : "group2" } ] }`

　findは第一引数に条件を、第二引数に取得フィールドを指定できます。こちらもjsonで指定します。SELECT _id,name,age FROM test WHERE age=80;みたいな感じです。

```
db.test.find({age: 80}, {_id:1,name:1,age:1})
```

　ちなみに、{age:80}で暗黙的にage=80となってますが、他の演算子も使えます。{age: {\$gt:80}}とか{age: {\$lte:80}}とかで動きます。>https://docs.mongodb.com/manual/reference/operator/query-comparison/

## Update
　続いてドキュメントを更新する手順です。Updateは細かい技が多いので、単純な更新のみを記載します。>https://docs.mongodb.com/v3.4/reference/method/db.collection.update/

```
db.test.update(
   {name: "mogamoga"},
   {name: "mogamoga", age: 10},
   {upsert: true}
)
```

　これでドキュメントがまるっと更新されます。_idは変わりませんが、それ以外の項目はDeleteしてInsertされた様な状態になります。Createした時はgroupsのフィールドがありましたが、上記Updateで消えてしまいます。
　指定したフィールドのみを更新して、それ以外のフィールドはそのままにしたい！という場合はfindAndModifyやfindOneAndUpdateを使います。説明は割愛します。>https://docs.mongodb.com/v3.4/reference/method/db.collection.findAndModify/

## Delete
　最後にドキュメントを削除する手順です。一件削除のdeleteOneと複数削除のdeleteManyがあります。一件削除のみの例としておきます。>https://docs.mongodb.com/v3.4/reference/method/db.collection.deleteOne/

```
db.test.deleteOne({_id: ObjectId("5a27da255b22277a949b2cab")})
```

　該当するidが無くてもエラーにはなりません。結果のdeletedCountが0になります。削除出来た場合は件数が返ってきます。
　条件の対象が文字列等であれば{name:"mogamoga"}とかでいいのですが、今回はidで検索するのでObjectIdで検索する必要があります。{_id:"5a27da255b22277a949b2cab"}だと消えないので該当無しになるので注意が必要です。

# おわりに
　後半適当になってますが、MongoDBについて記載しました。2017/12現在はver3.4ですが、これからのバージョンアップで更に良くなって行くはずです。　Mongoの強味に集計（Aggregate）がありますが、記事を変えて書いていこうと思います。最後までご覧頂きありがとうございました。