# mongoDB + Python
## mongoDBのセットアップ
**ローカルに作成する場合**(macOS)
1.install
```bash
brew tap mongodb/brew
brew install mongodb-community
```
2.起動
```bash
brew services start mongodb-community
```
3.DBへの接続
```bash
mongo
```
4.DB作成
```bash
use DB_NAME
```
5.コレクション追加(RDBでいうテーブル)
```bash
db.createCollection("COLLECTION_NAME")
```
6.ドキュメントの作成(RDBでいうロー)
```bash
db.users.insertOne({ hoge: "hogehoge", hage: 1})
```
## pythonライブラリ
- [pymogo](https://pypi.org/project/pymongo/)を使うのが主流っぽい
基本的な操作一覧
```python=
from pymongo import MongoClient
# 接続
def test_get_database_and_collection():
with MongoClient("172.17.0.2", 27017) as client:
test_db = client.test_db
users = test_db.users
assert users is not None
# ドキュメントの登録、取得
def test_document_insert_and_find_many():
with MongoClient("172.17.0.2", 27017) as client:
test_db = client.test_db
users = test_db.users
user = [
{"name": "taro", "age": 20, "email": "hoge@example.com"},
{"name": "hanako", "age": 36, "email": "hoge@example.com"},
{"name": "ken", "age": 23, "email": "hoge@example.com"}
]
users.insert_many(user)
assert users.count_documents({}) == 3
found_all_users = [user for user in users.find({}, sort = [("age", pymongo.DESCENDING)])]
assert found_all_users[0]["name"] == "taro"
assert len(found_all_users) == 3
```
## 触ってみた所感
- 操作感はかなり楽だった
- JSONで吐き出すことも容易そう
## mongoDBをどこに置くのが良いか
### mongoDB on EC2
[詳細](https://dev.classmethod.jp/articles/mongodb-on-ec2/)
- エンタープライズエディションとコミュニティエディションがある
- エンタープライズエディションでできること
- マネジメントサービスが利用できる(バックアップや監視ソリューション)
- SNMPモニタリングができる
- KerberosやLDAP認証が利用できる
- TableauなどのBIツールと連携可能な「MongoDB Connector for BI」が使える(Ver3.2以上)
- スキーマビジュアライゼーションツール「MongoDB Compass」が使える
- インメモリストレージエンジンが使える(Ver3.2.6以上)
### Amazon DocumentDB
- MongoDB のワークロードをサポートする、高速かつスケーラブルで可用性に優れたフルマネージド型のドキュメントデータベースサービス
- JSON データの保存、クエリ、およびインデックスを容易にする
### まとめ
- AWS的にはDocumentDBの方を推してそうな雰囲気
- EC2でやる方は普通にlinuxサーバーの上でmongoDB動かすのと変わらないような印象
### その他参考リンク
- https://aws.amazon.com/jp/quickstart/architecture/mongodb/
- https://docs.aws.amazon.com/ja_jp/quickstart/latest/mongodb/overview.html
- https://aws.amazon.com/jp/blogs/news/12-things-you-should-know-about-amazon-documentdb-with-mongodb-compatibility/
## ドキュメントの更新
### 更新方法
- findの代わりにupdateコマンドを使う
- 更新するドキュメントの条件を第1引数に渡して、第2引数に更新する内容を渡す
```
db.コレクション名.update({検索条件}, {更新内容})
```
- updateコマンドの第1引数の検索条件の書き方は、findコマンドの検索条件(クエリセレクタ)と全く同じ
### 注意点
- MongoDBのupdateは、第2引数で渡した内容で上書き保存する。
例:hogeさんの性別をXに上書きするとき次のように実行すると
```
> db.user.update({name:'hoge'}, {gender:'X'})
> db.user.find({}, {name:1, gender:1, _id:0})
{ "gender" : "X" }
{ "name" : "taro", "gender" : "m" }
{ "name" : "hanako", "gender" : "f" }
{ "name" : "ken", "gender" : "f" }
```
hogeさんのレコードが消えてしまう
上で行った処理は、hogeさんの性別を更新したのではなく、名前がhogeというドキュメントをgender:Xというドキュメントで上書きしたということになる。
- $setという修飾子を利用すれば解決する
```
> db.user.update({name:'hoge'}, {$set:{gender:'X'}})
> db.user.find({}, {name:1, gender:1, _id:0})
{ "gender" : "X", , "name" : "hoge" }
{ "name" : "taro", "gender" : "m" }
{ "name" : "hanako", "gender" : "f" }
{ "name" : "ken", "gender" : "f" }
```
- 存在しないフィールドを指定してドキュメントをアップデートすることも可能
## ユーザー認証
**関連リンク**
https://docs.mongodb.com/v3.2/reference/built-in-roles/#superuser-roles
https://qiita.com/h6591/items/68a1ec445391be451d0d
https://www.infoq.com/jp/articles/Starting-With-MongoDB/
- デフォルトでは認証なしで作成されてしまう
- 世の中にはたくさん認証なしで運用されてるmongoDBがあるらしい
**ユーザーの作り方**
- shell上でやる場合
1.ユーザー認証を有効にする
```
mongod --dbpath <directory> --auth
```
2.作成する
```
$ mongo
> use DB名
switched to db DB名
> db.createUser({user:"mongo", pwd:"18fuw63x", roles:["root"]})
Successfully added user: { "user" : "mongo", "roles" : [ "root" ] }
> exit
```
- pymongoで実行する場合
```python=
import pymongo
host = 'localhost'
port = 27017
db = 'admin'
client = pymongo.MongoClient(host, port)
client[db].add_user(
'admin',
'password',
roles=[
{
'role': 'userAdminAnyDatabase',
'db': db,
},
],
)
```
## django2とdjango3の大きな違い
- 現状Python 3.6、3.7、3.8のみサポートしている
- ASGI(非同期Webサーバー)対応
- 現状では非同期のviewやmiddlewareの作成はまだサポートしていない
- TextChoices、IntegerChoices、ChoicesをField.choicesとして列挙型が使えるようになった
- 使い方は[こちら](https://docs.djangoproject.com/ja/3.0/ref/models/fields/#enumeration-types)
- django3で消された機能
- django.db.backends.postgresql_psycopg2
- django.shortcuts.render_to_response()
- DEFAULT_CONTENT_TYPE
- HttpRequest.xreadlines()
- Field.from_db_value(),Expression.convert_value()
- QuerySet.earliest(),latest()
- django.utils.http.cookie_date()
- テンプレートタグのstaticfiles,admin_static
- django.contrib.staticfiles.templatetags.staticfiles.static()
## djangoでのconnection poolについて
- pymongoでサポートしていそうな雰囲気
- [公式ドキュメント](https://pymongo.readthedocs.io/en/stable/faq.html#how-does-connection-pooling-work-in-pymongo)