Mongodbの使い方

MacにHomebrewでインストールした際のメモです。

[参考記事](http://qiita.com/saba1024/items/f2ad56f2a3ba7aaf8521)

有名な無料資料 おすすめです↓
[mongodbの薄い本](http://www.cuspy.org/diary/2012-04-17/the-little-mongodb-book-ja.pdf)

## 用語
MongoDBは`ドキュメント志向`のデータベース

__RDB用語との対応表__

|RDB|MongoDB|
|:--|:--|
|テーブル構造|JSON形式|
|SQL文|Mongoクエリ|
|データベース|データベース|
|テーブル|コレクション|
|レコード|ドキュメント|
|フィールド（カラム）|フィールド|
|インデックス|インデックス|
|Primary key|_id|

ちなみに、なぜRDBの用語と対応する概念が存在するのに別な呼び方をするかというと、一見インターフェースは同じように見える・扱えるけど、データ構造や性質が異なる部分があるためらしいです。（薄い本参照）

例えば、下記↓

- レコードに該当するドキュメントの中には、値だけではなくフィールド名も保持している。

```
# 注意: _idは適当で、ドキュメント毎にユニークな値が生成される
{
	"myCollection": {
		{ "_id": "xxx", "foo": 1 } # ドキュメント1
		{ "_id": "yyy", "foo": 2 } # ドキュメント2
	}
}
```

- ドキュメント毎に、独自のフィールドを持つことができる。

```
{
	"myCollection": {
		{ "_id": "xxx", "foo": 1 } # ドキュメント1
		{ "_id": "yyy", "foo": 2, "bar": 2 } # ドキュメント2
		{ "_id": "zzz", "baz": 3,} # ドキュメント3
	}
}
```


## Macにインストール、設定、起動

```
# Homebrewでインストール
$ brew install mongodb

# データ格納用ディレクトリ作成
$ sudo mkdir -p /data/db/mongodb

# 所有者変更
$ sudo chown `whoami` /data/db/mongodb

# 初期化（&起動）
$ mongod --dbpath /data/db/mongodb

# Homebrewでデーモン化してプロセス起動
$ brew services start mongodb --dataPath=/data/db/mongodb

# もしくは普通にプロセス起動
$ mongod --dataPath=/data/db/mongodb
```
> `brew services start mongodb`の後に`brew services list`して、ステータスが`started`になってなかったら`brew services restart mongodb`で再起動する

## 基本コマンド

```
# 接続
$ mongo

# DB一覧
> show dbs

# DB切り替え
> use mydb

# DBの構造
> db.stats()

# ドキュメント挿入
> db.mycollection.insert(
  {
    "name" : "Taro",
    "gender": "m",
    "attribute" : {
      "hobby" : [
        ”game”,
        "cook"
      ]
    }
  },
  {
    "name" : "Hanako",
    "gender": "f",
    "attribute" : {
      "hobby" : [
        ”movie”
      ]
    }
  }
)

# collection一覧
> show collections

# ドキュメント全取得
> db.mycollection.find()

# 特定のドキュメント取得
# 引数のオブジェクトをセレクタと呼ぶ
# 第1引数に取得したいドキュメントの条件、第2引数に取得したいフィールド
# 1:取得する, 0:取得しない（_idはデフォルト1）
> db.mycollection.find(
	{name: "Taro"},
	{
	  _id: 0,
	  attribute: {
	    hobby: 1
	  }
	}
)

# ドキュメント更新
# $setを更新修飾子と呼ぶ。これがないとドキュメント全体が{"gemder": 1}に置き換わる
> db.mycollection.update(
	{name: "Taro"},
	{$set: {"gender": "f"}}
)

# upsert（なかったら追加）
# updateの第3引数にtrue。$incはなかったらインクリメントという動作になる
> db.counter.update(
	{type: "success"},
	{$inc: {count: 1}},
	true
)

# 複数同時更新
# 第4引数にtrue、第3引数もtrueだと複数同時upsert
> db.user.update(
	{},
	{$set: {gender: "m"}},
	false,
	true
)

# ドキュメント削除
> db.mycollection.remove({name: "Jiro"})

# collection削除
> db.mycollection.drop()

# DB削除
> db.dropDatabase()

# 終了
> exit
```
> 補足
 - 存在しないDB、collectionにドキュメントを追加するとDB、collectionも追加される
 - collection削除時にDB内のcollectionがなくなるとDBも削除される


## 更新修飾子
`update`で利用できる修飾子の一覧表

|更新修飾子|意味|
|---|---|
|$set|フィールドの一部を更新|
|$inc|フィールドの値を増やす|
|$push|フィールドに値を追加|


## 関数
```
# sort（1:昇順、-1:降順）
$ db.user.find().sort({age:1})

# count
$ db.user.count()
```
> 補足
`sum`とかはライブラリを併用しないと利用できないという不便さがあるが、関数を保存・呼び出し出来たり、`forEach, map`が使えたりという反則技が存在する。
[mongoシェルでServer-Side Functionsをsave＆loadして使ってみる](http://tweeeety.hateblo.jp/entry/20140319/1395235283)


## 比較演算子
|SQL|MongoDB|概要|サンプル|
|-----|-------|----|-------|
|<|$lt|未満|{age: {$lt: 100}}|
|<=|$lte|以下|{age: {$lte: 100}}|
|>|$gt|より大きい|{age: {$gt: 100}}|
|>=|$gte|以上|{age: {$gte: 100}}|
|!=|$ne|等しくない|{name: {$ne: 'mr.a'}}|
|なし|$exists|フィールドの存在チェック|db.mycol.find({hoge: {$exists: false}})|
|OR|$or|$orで指定する条件のいずれかを満たすものを抽出| db.mycol.find({$or: [{loves: 'apple'},{loves: 'energon'}]})|