はじめてのmongodb


起動

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

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

起動

docker-compose up -d

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

# 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したものです)

csvに書き出すの便利そう。

データの変更もできます! 素敵だ。

CLI接続

# コンテナに入る
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してみます

> 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引数で渡した内容で上書き保存します。
コレは罠です。非常に危険な罠です。

これが
{ "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と違って簡単にフィールド(カラム、列)の追加ができます。
というのも、コレクション(テーブル)自体にフィールド情報が定義されているわけではなく、あくまでドキュメント(レコード、行)単位にフィールド情報が保持されているためです。

ん??

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

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

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