Azure Cosmos DB - 基本操作（Python）

# 目的

`Azure SDK for Python`を使用して`Azure Cosmos DB`の基本操作を確認する

# 料金

[公式](https://azure.microsoft.com/ja-jp/pricing/details/cosmos-db/)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/78e6498c-ef8c-0d2c-03d9-4e5ffb0aac9b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/9e2cf605-b421-6793-68bf-872cb8931529.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/e00707d4-98d4-b5fa-2ea9-f565d604cd4a.png)

上記より、
スループットは最小の400RU/秒、ストレージは100GBとした場合の1か月（30日）の料金は以下

スループット： 0.896 * 4 * 24 * 30 = 2580（円）
ストレージ： 28 * 100 = 2800（円）
合計： 5380（円）

# 無料枠

[公式](https://docs.microsoft.com/ja-jp/azure/cosmos-db/create-sql-api-python#create-a-database-account)
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/36860add-bd4f-9727-a004-00a66bfe17b4.png)

Azure Cosmos DBアカウントの作成時にFreeレベルの割引の適用を行うことで、
最初の`400 RU/秒`と`5GB`のストレージを無料で使用することができる

ただし、Freeレベルの割引の適用ができるAzure Cosmos DBアカウントは、Azure サブスクリプションにつき1つまで
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/0c64f912-33ee-8073-ea38-4bf8dcb03918.png)

アカウント内にデータベースを作成すると最小400RU/秒のスループット設定が必要となるため、
複数のデータベースを作成すると、2つ目以降のデータベースは無料枠外となる

# 基本操作

## 前提

[公式](https://docs.microsoft.com/ja-jp/azure/cosmos-db/create-sql-api-python#create-a-database-account)
ドキュメントを参考にAzure Cosmos DBのアカウント、データベース、コンテナは作成済
以下2つのアイテムをコンテナに登録済

```json
{
  "id": "AndersenFamily",
  "category": "category1",
  "lastName": "Andersen",
  "address": {
      "state": "WA",
      "county": "King",
      "city": "Seattle"
      },
  "creationDate": 1431620472,
  "isRegistered": true
}
```
```json
{
  "id": "WakefieldFamily",
  "category": "category1",
  "lastName": "Wakefield",
  "address": {
      "state": "NY",
      "county": "Manhattan",
      "city": "NY"
      },
  "creationDate": 1431610472,
  "isRegistered": false
}
```

## 実装コード

Azure Cosmos DBのインスタンスを、エンドポイントURL＋キーまたは、接続文字列を使用して生成
DB操作として、アイテムの追加、全アイテムリード、1アイテムリード、クエリ、アイテム削除を実施

```python
from azure.cosmos import exceptions, CosmosClient, PartitionKey

endpoint = ''
key = ''
connectionString = ''

def main():
  
#  client = CosmosClient(endpoint, key)
  client = CosmosClient.from_connection_string(connectionString)

  databaseName = 'tasks'
  containerName = 'items'

  db = client.get_database_client(databaseName)
  container = db.get_container_client(containerName)

  newItem = {
    "id": "MillerFamily",
    "category": "category1",
    "lastName": "Miller",
    "address": {
        "state": "WA",
        "county": "King",
        "city": "Seattle"
        },
    "creationDate": 1431600472,
    "isRegistered": True
  }

  item = container.create_item(newItem)
  print(' --- create_item --- ')
  print(item)
  print()

  items = container.read_all_items(max_item_count=5)
  print(' --- read_all_items --- ')
  print(list(items))
  print()

  item = container.read_item('MillerFamily', 'category1')
  print(' --- read_item --- ')
  print(item)
  print()

  # クエリ条件： id = 'WakefieldFamily'
　# 取得プロパティ： 全て
  query = "SELECT * FROM items i WHERE i.id = 'WakefieldFamily'"
#  items = container.query_items(query, partition_key='category1')
  items = container.query_items(query, enable_cross_partition_query=True)
  print(' --- query_items 1 --- ')
  print(list(items))
  print()

  # クエリ条件： lastName = 'Andersen'
　# 取得プロパティ： 全て
  query = "SELECT * FROM items i WHERE i.lastName = 'Andersen'"
  items = container.query_items(query, enable_cross_partition_query=True)
  print(' --- query_items 2 --- ')
  print(list(items))
  print()

  # クエリ条件： address.state = 'WA'
　# 取得プロパティ： 全て
  query = "SELECT * FROM items i WHERE i.address.state = 'WA'"
  items = container.query_items(query, enable_cross_partition_query=True)
  print(' --- query_items 3 --- ')
  print(list(items))
  print()

  # クエリ条件： id = 'WakefieldFamily'
　# 取得プロパティ： address.state、address.city
  query = "SELECT i.address.state, i.address.city FROM items i WHERE i.id = 'WakefieldFamily'"
  items = container.query_items(query, enable_cross_partition_query=True)
  print(' --- query_items 4 --- ')
  print(list(items))
  print()

  container.delete_item('MillerFamily', 'category1')

main()
```
以下、実行結果
※Azure Cosmos DBで自動的に追加されるプロパティは出力内容から削除

```:実行結果
 --- create_item ---
{'id': 'MillerFamily', 'category': 'category1', 'lastName': 'Miller', 'address': {'state': 'WA', 'county': 'King', 'city': 'Seattle'}, 'creationDate': 1431600472, 'isRegistered': True}

 --- read_all_items ---
[{'id': 'AndersenFamily', 'category': 'category1', 'lastName': 'Andersen', 'address': {'state': 'WA', 'county': 'King', 'city': 'Seattle'}, 'creationDate': 1431620472, 'isRegistered': True}, {'id': 'WakefieldFamily', 'category': 'category1', 'lastName': 'Wakefield', 'address': {'state': 'NY', 'county': 'Manhattan', 'city': 'NY'}, 'creationDate': 1431610472, 'isRegistered': False}, {'id': 'MillerFamily', 'category': 'category1', 'lastName': 'Miller', 'address': {'state': 'WA', 'county': 'King', 'city': 'Seattle'}, 'creationDate': 1431600472, 'isRegistered': True}]

 --- read_item ---
{'id': 'MillerFamily', 'category': 'category1', 'lastName': 'Miller', 'address': {'state': 'WA', 'county': 'King', 'city': 'Seattle'}, 'creationDate': 1431600472, 'isRegistered': True}

 --- query_items 1 ---
[{'id': 'WakefieldFamily', 'category': 'category1', 'lastName': 'Wakefield', 'address': {'state': 'NY', 'county': 'Manhattan', 'city': 'NY'}, 'creationDate': 1431610472, 'isRegistered': False}]

 --- query_items 2 ---
[{'id': 'AndersenFamily', 'category': 'category1', 'lastName': 'Andersen', 'address': {'state': 'WA', 'county': 'King', 'city': 'Seattle'}, 'creationDate': 1431620472, 'isRegistered': True}]

 --- query_items 3 ---
[{'id': 'AndersenFamily', 'category': 'category1', 'lastName': 'Andersen', 'address': {'state': 'WA', 'county': 'King', 'city': 'Seattle'}, 'creationDate': 1431620472, 'isRegistered': True}, {'id': 'MillerFamily', 'category': 'category1', 'lastName': 'Miller', 'address': {'state': 'WA', 'county': 'King', 'city': 'Seattle'}, 'creationDate': 1431600472, 'isRegistered': True}]

 --- query_items 4 ---
[{'state': 'NY', 'city': 'NY'}]
```

### 使用クラス

- [CosmosClient Class](https://docs.microsoft.com/en-us/python/api/azure-cosmos/azure.cosmos.cosmos_client.cosmosclient?view=azure-python)
- [DatabaseProxy Class](https://docs.microsoft.com/en-us/python/api/azure-cosmos/azure.cosmos.databaseproxy?view=azure-python)
- [ContainerProxy Class](https://docs.microsoft.com/en-us/python/api/azure-cosmos/azure.cosmos.containerproxy?view=azure-python)

### インデックスについて

[Azure Cosmos DB のインデックス作成 - 概要](https://docs.microsoft.com/ja-jp/azure/cosmos-db/index-overview)
すべてのアイテムのすべてのプロパティに自動的にインデックスが作成されるため、基本的にインデックスを作成する必要はない
[Azure Cosmos DB での JSON の使用](https://docs.microsoft.com/ja-jp/azure/cosmos-db/sql-query-working-with-json)
入れ子になったプロパティを含め、すべてのプロパティでクエリが可能