はじめてのmongodb

# 起動

dockerでmongodbと、データビューアーのmongo-express２つを起動させます。

```yml
version: '3.1'

services:

  mongo:
    image: mongo
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: example

  mongo-express:
    image: mongo-express
    restart: always
    ports:
      - 8081:8081
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: root
      ME_CONFIG_MONGODB_ADMINPASSWORD: example
```
> https://hub.docker.com/_/mongo

起動

```ruby
docker-compose up -d
```

mongodbとmongo expressの2コンテナが起動します

```ruby
# docker ps | grep mongo
b8f3154dda29        mongo-express                               "tini -- /docker-ent…"   34 minutes ago      Up 33 minutes       0.0.0.0:8082->8081/tcp           mongo_mongo-express_1
06e8e28840bb        mongo                                       "docker-entrypoint.s…"   35 minutes ago      Up 33 minutes       27017/tcp                        mongo_mongo_1
```

# mongo-express
mongo-expressは こんなurlで見れる
http://localhost:8081/

こんな感じでドキュメントをブラウザから閲覧可能です（データはこの記事の↓の方でinsertしたものです）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24737/b86db615-5d77-afce-f6f6-19097a84b3a8.png)

csvに書き出すの便利そう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24737/eef0d27c-ed95-ec02-750d-2dfd5f9b767e.png)

データの変更もできます！ 素敵だ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24737/09ffb747-4e74-de98-1c9e-00791b9d74cd.png)



# CLI接続

```ruby
# コンテナに入る
docker exec -it mongo_mongo_1 bash

# cli起動
root@06e8e28840bb:/# mongo -u root -p example
...
...
...
>
```
接続できました。username/passwordは MONGO_INITDB_ROOT_USERNAME/PASSWORD でセットしたものです。


# 使ってみる
神記事をなぞって、大事なところを抜き出してみます。

> MongoDB超入門
> https://qiita.com/saba1024/items/f2ad56f2a3ba7aaf8521

なんとびっくり、databaseの作成は超簡単

```
> use study
```

createじゃないんかい！ useだけで作られる。素敵！！

データ入れながらselectしてみます

```moon
> db.stats()

# records 登録
db.user.insert({name:'mr.a', age:10, gender:'m', hobbies:['programming']});
db.user.insert({name:'mr.b', age:20, gender:'m', hobbies:['vi']});
db.user.insert({name:'ms.c', age:30, gender:'f', hobbies:['programming', 'vi']});
db.user.insert({name:'ms.d', age:40, gender:'f', hobbies:['cooking']});

# select * from study
> db.user.find()

# where句
 db.user.find( {name:'ms.c'} )

配列(not dict) は文字列のように検索できる
> db.user.find({hobbies:'programming'})
{ "_id" : ObjectId("5ee1a837b84ea8cc6e82073f"), "name" : "ms.c", "age" : 30, "gender" : "f", "hobbies" : [ "programming", "vi" ] }
```

### update文
MongoDBのupdateは、第2引数で渡した内容で上書き保存します。
コレは罠です。非常に危険な罠です。

```ruby
これが
{ "name" : "mr.a", "age" : 10, "gender" : "m", "hobbies" : [ "programming" ] }

updateすると
db.user.update({name:'mr.a'}, {gender:'X'})

こうなっちゃう
{ "gender" : "X" }
```

NoSQLあるある。

> 実はこれ、mr.aさんの性別を更新したというよりも、名前がmr.aというドキュメントをgender:Xというドキュメントで上書きしたということになります。

上書きというより置き換えた感じ。

> じゃあどうするんだよ。。。という話ですが、そのために、$setという修飾子を利用する必要があります。
本来は、$setを使って以下のようにする必要があったわけです。

```
> db.user.update({name:'mr.a'}, {$set:{gender:'X'}})
```

elasticsearchよりは簡単かも。NoSQL系はみんなこうなのかな。updateめんどくて嫌になっちゃうね。

で、このupdateにも罠がある。

> コレだと、MongoDBが最初に見つけた1件のみしか更新されません。
> 同時に2件以上の該当レコードを一気に更新するには、第4引数にtrueを渡してあげる必要があります。

```
> db.user.update({}, {$set:{gender:'X'}}, false, true)
```

初見殺しすぎる・・・



### upsert
upsert句は存在せず、updateの第3引数をtrueという残念な仕様らしい。あるだけいいけど

```
> db.counter.update( {type:'error'} ,{$inc:{count:1}}, true)
```




# カラム追加
今日知りたかったのはここ。elasticsearchみたいにらくーにカラム追加できるのかってとこ。結論：elasticsearchよりさらに楽！

> 結構重要な点だと思いますが、MongoDBでは、RDBMSと違って簡単にフィールド（カラム、列）の追加ができます。
というのも、コレクション（テーブル）自体にフィールド情報が定義されているわけではなく、あくまでドキュメント（レコード、行）単位にフィールド情報が保持されているためです。

ん？？

> ドキュメント（レコード、行）単位にフィールド情報が保持されているためです。
> ドキュメント（レコード、行）単位にフィールド情報が保持されているためです。
> ドキュメント（レコード、行）単位にフィールド情報が保持されているためです。

マジカ！！！！　そもそもカラムという考え方がないのか。全レコード独立してるのか。すげぇ！！！！！





勉強になりました！！使ってみよう！