---
# System prepended metadata

title: mongoDB + Python

---

# 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)
