MongoDB 4.0のCentOS7へのインストールと基本操作

ドキュメント指向のNoSQLとして人気があり、Web系のログ蓄積等で耳にするMongoDBを、[こちら](https://qiita.com/daskepon/items/aa93f8955407da0cb896)を参考に触ってみたのでまとめます。

##MongoDBの主な特徴
* スキーマレス（データ構造の事前定義が不要）
* JOIN、トランザクションのサポートはない
* 水平分散による拡張性

##MongDBのインストール

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

yum install mongodb-org
systemctl start mongod
systemctl enable mongod
```

デフォルトは27017でListen

```
[root@localhost ~]# lsof -i :27017
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
mongod  10642 mongod   10u  IPv4  49590      0t0  TCP localhost:27017 (LISTEN)

firewall-cmd --add-port=27017/tcp --zone=public --permanent
firewall-cmd --reload
```

##Mongoシェルの起動
コンソールでmongoと入力

```
[root@localhost ~]# mongo
MongoDB shell version v4.0.3
connecting to: mongodb://127.0.0.1:27017
Implicit session: session { "id" : UUID("c94e5484-bc07-448d-a696-552294043074") }
MongoDB server version: 4.0.3
・・・・
```

test dbを作成（＋接続も同時に実施される）

```
> use test
switched to db test
```

DBの状態を確認

```
> db.stats()
{
        "db" : "test",
        "collections" : 0,
        "views" : 0,
        "objects" : 0,
        "avgObjSize" : 0,
        "dataSize" : 0,
        "storageSize" : 0,
        "numExtents" : 0,
        "indexes" : 0,
        "indexSize" : 0,
        "fileSize" : 0,
        "fsUsedSize" : 0,
        "fsTotalSize" : 0,
        "ok" : 1
}
```

テストデータの挿入

```
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']});
```

データの確認: findがSQLのSELECT

```
> db.user.find()
{ "_id" : ObjectId("5bd6be298d280c3a544ebce6"), "name" : "mr.a", "age" : 10, "gender" : "m", "hobbies" : [ "programming" ] }
{ "_id" : ObjectId("5bd6be298d280c3a544ebce7"), "name" : "mr.b", "age" : 20, "gender" : "m", "hobbies" : [ "vi" ] }
{ "_id" : ObjectId("5bd6be298d280c3a544ebce8"), "name" : "ms.c", "age" : 30, "gender" : "f", "hobbies" : [ "programming", "vi" ] }
{ "_id" : ObjectId("5bd6be2b8d280c3a544ebce9"), "name" : "ms.d", "age" : 40, "gender" : "f", "hobbies" : [ "cooking" ] }
>
```

##RDBとMongoDBの用語比較

|RDB　　  |MongoDB  |  
|---|---|---|
|データベース |データベース |
|表 |コレクション |
|行（レコード）|ドキュメント |
|列 |フィールド |

##条件演算
クエリセレクタ：{フィールド名:値}で条件を渡す
年齢が20歳以上の男性を抽出　　[比較演算子](https://docs.mongodb.com/manual/reference/operator/query/)

```
> db.user.find({age:{$gte:20}, gender:'m'})
{ "_id" : ObjectId("5bd6be298d280c3a544ebce7"), "name" : "mr.b", "age" : 20, "gender" : "m", "hobbies" : [ "vi" ] }

```

##配列
配列もその他のフィールド（列）と同様に検索可能

```
>  db.user.find({hobbies:'cooking'})
{ "_id" : ObjectId("5bd6be2b8d280c3a544ebce9"), "name" : "ms.d", "age" : 40, "gender" : "f", "hobbies" : [ "cooking" ] }
```

##取得フィールド（列）の指定
SELECT 列名相当は、findの第2引数に取得するフィールド名を指定
{フィールド名：0}以外の数字で表示、{フィールド名:0}で非表示

```
> db.user.find({}, {age:0})
{ "_id" : ObjectId("5bd6be298d280c3a544ebce6"), "name" : "mr.a", "gender" : "m", "hobbies" : [ "programming" ] }
{ "_id" : ObjectId("5bd6be298d280c3a544ebce7"), "name" : "mr.b", "gender" : "m", "hobbies" : [ "vi" ] }
{ "_id" : ObjectId("5bd6be298d280c3a544ebce8"), "name" : "ms.c", "gender" : "f", "hobbies" : [ "programming", "vi" ] }
{ "_id" : ObjectId("5bd6be2b8d280c3a544ebce9"), "name" : "ms.d", "gender" : "f", "hobbies" : [ "cooking" ] }
> db.user.find({}, {age:1})
{ "_id" : ObjectId("5bd6be298d280c3a544ebce6"), "age" : 10 }
{ "_id" : ObjectId("5bd6be298d280c3a544ebce7"), "age" : 20 }
{ "_id" : ObjectId("5bd6be298d280c3a544ebce8"), "age" : 30 }
{ "_id" : ObjectId("5bd6be2b8d280c3a544ebce9"), "age" : 40 }
```

##Update
下記で更新可能
db.コレクション名.update({検索条件}, {$set：{更新内容}})
※$setがないと、検索条件列が更新内容の値でUpdateされるので注意

```
> db.user.find({name:"mr.a"})
{ "_id" : ObjectId("5bd6be298d280c3a544ebce6"), "name" : "mr.a", "age" : 10, "gender" : "m", "hobbies" : [ "programming" ] }

>  db.user.update({name:'mr.a'}, {$set:{gender:'X'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

> db.user.find({name:"mr.a"})
{ "_id" : ObjectId("5bd6be298d280c3a544ebce6"), "name" : "mr.a", "age" : 10, "gender" : "X", "hobbies" : [ "programming" ] }
```

##特定ドキュメント（行）にフィールド（列）追加も可能
存在しないフィールドを更新し、名前がmr.bの人のレコードに、hoge:111という新しいフィールドを追加

```
> db.user.update({name:'mr.b'}, {$set:{hoge:111}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5bd6be298d280c3a544ebce6"), "name" : "mr.a", "age" : 10, "gender" : "X", "hobbies" : [ "programming" ] }
{ "_id" : ObjectId("5bd6be298d280c3a544ebce7"), "name" : "mr.b", "age" : 20, "gender" : "m", "hobbies" : [ "vi" ], "hoge" : 111 }
```

##Upsert
データが存在しなければINSERT、存在すればUPDATE
存在しない＝コレクション（表）が無い場合と、該当ドキュメント（行）が無い場合
共になければ自動的に作成、あればUPDATEされる

例）db.counter.update( {type:'success'} ,{$inc:{count:1}}, true)
$incは、対象の値を増分

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

> db.counter.find()
{ "_id" : ObjectId("5bd7b8b5d6949f96aeb75451"), "type" : "error", "count" : 3 }
{ "_id" : ObjectId("5bd7b8fcd6949f96aeb7545a"), "type" : "success", "count" : 1 }

```

##複数件同時更新
db.user.update({}, {$set:{gender:'X'}},false,true)
※第三引数：upsert (false:存在しないレコードは更新しない)
第四引数：trueにして、複数件を更新

```
> db.user.find({},{_id:0})
{ "name" : "mr.a", "age" : 10, "gender" : "X", "hobbies" : [ "programming" ] }
{ "name" : "mr.b", "age" : 20, "gender" : "m", "hobbies" : [ "vi" ], "hoge" : 111 }
{ "name" : "ms.c", "age" : 30, "gender" : "f", "hobbies" : [ "programming", "vi" ] }
{ "name" : "ms.d", "age" : 40, "gender" : "f", "hobbies" : [ "cooking" ] }

> db.user.update({}, {$set:{gender:'X'}}, false, true)
WriteResult({ "nMatched" : 4, "nUpserted" : 0, "nModified" : 3 })

> db.user.find({},{_id:0})
{ "name" : "mr.a", "age" : 10, "gender" : "X", "hobbies" : [ "programming" ] }
{ "name" : "mr.b", "age" : 20, "gender" : "X", "hobbies" : [ "vi" ], "hoge" : 111 }
{ "name" : "ms.c", "age" : 30, "gender" : "X", "hobbies" : [ "programming", "vi" ] }
{ "name" : "ms.d", "age" : 40, "gender" : "X", "hobbies" : [ "cooking" ] }
```

##Remove
ドキュメント（行）削除
db.user.remove()

````
> db.user.remove({age:{$gte:30}})
WriteResult({ "nRemoved" : 2 })

> db.user.find({},{_id:0})
{ "name" : "mr.a", "age" : 10, "gender" : "X", "hobbies" : [ "programming" ] }
{ "name" : "mr.b", "age" : 20, "gender" : "X", "hobbies" : [ "vi" ], "hoge" : 111 }
```

##Sort,Count
sort: {フィールド:1（昇順）}、{フィールド:ｰ1（降順）}
count: count()

```
> db.user.find({},{_id:0}).sort({age:1})
{ "name" : "mr.a", "age" : 10, "gender" : "X", "hobbies" : [ "programming" ] }
{ "name" : "mr.b", "age" : 20, "gender" : "X", "hobbies" : [ "vi" ], "hoge" : 111 }
> db.user.find({},{_id:0}).sort({age:-1})
{ "name" : "mr.b", "age" : 20, "gender" : "X", "hobbies" : [ "vi" ], "hoge" : 111 }
{ "name" : "mr.a", "age" : 10, "gender" : "X", "hobbies" : [ "programming" ] }

> db.user.find({}).count()
2
```