【MongoDB】0から調べたMongoDB

## きっかけ
- とある案件でAWS DocumentDBを構築することになり、検証も兼ねてクエリ等実行する必要があったため、書籍を読んで勉強しました。

## 注意
- 書籍（英語）を読みながらメモをとったため、そもそもの理解が間違えている可能性もありますので、参考にされる際はご留意ください。

### 基礎コンセプト
- ドキュメント
	- RDBの行に当たる
	- キーはデータ型、大文字小文字で区別される
	- キーの重複は不可
- コレクション
	- RDBのテーブルに当たる
	- Dynamic Schema(コレクション内に異なる形のドキュメントを持つ)
	- コレクションを組織するためにサブコレクションという命名方法が使える(.で分ける。eg) blog.posts, blog.authors`)
		-	機能上のメリットはなし

### ツール
- MongoDB shell
- MongoDB client
	- Shellによる基本操作(CRUD)
		- Create
			- `db.movies.insertOne({name : "hogehoge"})`
		- Read
			- `db.movies.findOne()`
		- Update
			- `db.movies.updateOne({name : "hogehoge"},... {$set : {address: []}})`
		- Delete
			- `db.movies.deleteOne({name : "hogehoge"})`

### データ型
- Null
	- `{"x" : null}`
- ブーリアン
	- `{"x" : true}`
- 数値
	- `{"x" : 3.14}`
- 文字列
	- `{"x" : "hogehoge"}`
- 日付
	- `{"x" : new Date()}`
- 正規表現
	- `{"x" : /hogehoge/i}`
- 配列
	- `{"x" : ["a", "b", "c"]}`
- 組み込みドキュメント
	- `{"x" : {"hogehoge" : "fugafuga"}}`
- オブジェクトID
	- `{"x" : ObjectId()}`
- バイナリデータ
- Javascriptコード

### findクエリー
- `db.test.find()`
	- コレクションtest内の全ドキュメント取得
- `db.test.find({"hogehoge" : "fugafuga"})`
	- コレクションtest内のキーhogehogeの値がfugafugaのドキュメントを取得
- `db.test.find({"hogehoge" : "fugafuga", "foo" : "bar"})`
	- コレクションtest内のキーhogehogeの値がfugafugaかつキーfooの値がbarのドキュメントを取得
- `db.test.find({}, {"hogehoge" : 1, "foo" : 1})`
	- コレクションtest内の全ドキュメントのキー　hogehoge, fugafugaと_idのみを取得
- `db.test.find({}, {"hogehoge" : 0})`
	- コレクションtest内の全ドキュメントのキー　hogehoge以外を取得
- `db.test.find({}, {"hogehoge" : 1, "_id" : 0})`
	- "_id" : 0とすることで_idを除外可能

- 演算子
	- `$lt` : <
	- `$lte` : <=
	- `$gt` : >
	- `$gte` : >=
	- `$ne` : not equal
	- `$not`: 否定
		- eg) `db.person.find({"age" : {"$gte" : 18, "$lte" : 30}})`

- OR検索
	- `db.test.find({"hogehoge" : { $in :["fugafuga", "piyopiyo"]}})`
		- コレクションtest内のキーhogehogeの値がfugafugaもしくはpiyopiyoのドキュメントを取得
	- `db.test.find({"hogehoge" : { $nin :["fugafuga", "piyopiyo"]}})`
		- コレクションtest内のキーhogehogeの値がfugafugaもしくはpiyopiyoでないドキュメントを取得
		- `db.test.find({"$or" : [{"hogehoge" : "fugafuga", "foo" : "bar"}]})`
		- コレクションtest内のキーhogehogeの値がfugafugaもしくはキーfooの値がbarであるドキュメントを取得
	
	- 型検索
		- `db.test.find({"hogehoge" : null})`
			- コレクションtest内のキーhogehogeの値がnullのドキュメントを取得
			- また、nullの場合、そのキー項目が存在しないドキュメントも取得
				- `db.test.find({"hogehoge" : {"$eq" : null, "$exists" : true}}))`
					- コレクションtest内のキーhogehogeがあり、値がnullのドキュメントを取得

	- 正規表現
		- `db.test.find({"hogehoge" : "$regex" : /fugafuga/i})`
			- コレクションtest内のキーhogehogeの値がfugafuga (大文字小文字を問わない)のドキュメントを取得
			- 正規表現の一致にPerl Compatible Regular Expressionを使用
		
	- 配列検索
		- 前提: `{"fruit" : ["apple", "banana", "peach"]}`
		-  `db.food.find({"fruit" : "banana"})`
			- コレクションfood内のキーfruitの値がbananaを含むドキュメントを取得
		-  `db.food.find({"fruit" : {$all: ["banana", "apple"]}})`
			- コレクションfood内のキーfruitの値にbananaとappleの両方を含むドキュメントを取得
			- リスト内の項目順は関係なし
		-	`db.food.find({"fruit.1" : "banana"})`
			- コレクションfood内のキーfruitの２番目の値がbananaであるドキュメントを取得
			- 配列のインデックスは0始まり

		- `db.food.find({"fruit" : {"$size" : 3}})`
			- コレクションfood内のキーfruitの値の個数が3つであるドキュメントを取得
		- `db.food.find({"fruit" : {"$size" : {"$gt" : 3}}})`
			- コレクションfood内のキーfruitの値の個数が3つより大きいドキュメントを取得

		- `db.food.find({"fruit" : "banana"},{"fruit" : {"$slice" :2 }})`
			- コレクションfood内のキーfruitの値がbananaを含むドキュメントでキーfruitの値の上位2つを取得
		- `db.food.find({"fruit" : "banana"},{"fruit" : {"$slice" :-2 }})`
			- コレクションfood内のキーfruitの値がbananaを含むドキュメントでキーfruitの値の下位2つを取得
		- `db.food.find({"fruit" : "banana"},{"fruit" : {"$slice" :[2,2] }})`
			- コレクションfood内のキーfruitの値がbananaを含むドキュメントでキーfruitの値の2番目から2つを取得
		- `db.food.find({"fruit" : "banana"},{"fruit".$ : 1)`
			- コレクションfood内のキーfruitの値がbananaを含むドキュメントでキーfruitの項目のみを取得

	- 組み込みドキュメント検索
		- `db.people.find({"name.first" : "Joe", "name.last" : "Schmoe"})`
			- ドット記法を用いてクエリ実行可能

	-	whereクエリ
		-	JavaScriptをクエリの一部として利用可能
	
	- カーソル
		- findの結果はカーソルとして返却される
		- nextメソッドやhasNextメソッドをもち、foreachでループを実行可能
		- limit(取得上限)、skip(結果のスキップ)、sort(並び替え)が可能
			- 大規模なskip処理はパフォーマンスが下がるので避けるべき

### Index
- 実行計画の取得
	- .explain("executionStats") でCRUD実行時の実行計画を取得

- Indexの作成
	- インデックスを作成する項目は頻度の高いクエリの特定、クエリ速度の考慮、クエリの共通項目の特定が必要
	- db.test.createIndex({"hogehoge" : 1})
		- コレクションtest内のキーhogehogeにインデックスを作成
	- db.test.createIndex({"foo" : 1 , "hogehoge" : 1})
		- コレクションtest内のキーfoo, hogehogeに複合インデックスを作成

- 複合キーのインデックス優先順
	- 条件フィルタのキーが最優先
	- ソートに使用されるキーが次点
	- 複数値フィルタのキーが最後
		- 参考: https://christina04.hatenablog.com/entry/2015/03/03/125643

- 組み込みドキュメントのインデックス
	- `db.test.createIndex({"hogehoge.hoge" : 1})`


## 参考書籍

[MongoDB: The Definitive Guide, 3rd　Edition](https://www.oreilly.com/library/view/mongodb-the-definitive/9781491954454/)