pymongoを使用してPythonからOracle Database 23c Freeにアクセスし、JSON Relational Duality Viewをコレクションとして操作してみた

# はじめに

こちらの記事でMongoDB ShellからOracle Database 23c FreeにアクセスしてJSON Relational Duality Viewをコレクションとして操作してみた際の検証内容を書きました。

https://qiita.com/500InternalServerError/items/bfd5ede82b9514a4e52e

この記事では、PythonからOracle Database 23cにOracle Database API for MongoDB経由でアクセスして、JSON Relational Duality Viewに対するドキュメント操作を行ってみました。
PythonからOracle Database API for MongoDBへのアクセスにはpymongoドライバーを使用しました。

# 1. 事前準備
JSON Relational Duality Viewのベースとなっている各表のデータを削除しておきます。
```
[oracle@oracle23c ~]$ sqlplus "mongo_test/MyPassword1!"@freepdb1

SQL*Plus: Release 23.0.0.0.0 - Developer-Release on Wed May 17 13:43:24 2023
Version 23.2.0.0.0

Copyright (c) 1982, 2023, Oracle.  All rights reserved.

Last Successful login time: Wed May 17 2023 13:43:06 +00:00

Connected to:
Oracle Database 23c Free, Release 23.0.0.0.0 - Developer-Release
Version 23.2.0.0.0

SQL> 
SQL> TRUNCATE TABLE driver_race_map;

Table truncated.

SQL> TRUNCATE TABLE race;

Table truncated.

SQL> TRUNCATE TABLE driver;
Table truncated.

SQL> TRUNCATE TABLE team;

Table truncated.

SQL>
```
PythonからMongoDBにアクセスするためのドライバーpymongoをインストールします。
```
[opc@23c ~]$ sudo pip3 install pymongo
WARNING: Running pip install with root privileges is generally not a good idea. Try `pip3 install --user` instead.
Collecting pymongo
  Downloading https://files.pythonhosted.org/packages/10/3b/46541b4ee3000019b8ef5b1847292ddc77f492c162bc4d49c424db7fc97a/pymongo-4.1.1-cp36-cp36m-manylinux1_x86_64.whl (464kB)
    100% |████████████████████████████████| 471kB 3.6MB/s 
Installing collected packages: pymongo
Successfully installed pymongo-4.1.1
[opc@23c ~]$
```

# 2. pymongoを使用してPythonからOracle Database 23c Freeにアクセスする

Pythonをインタラクティブモードで起動します。
```
[opc@oracle23c ~]$ python
Python 3.6.8 (default, Feb 21 2023, 05:30:22) 
[GCC 8.5.0 20210514 (Red Hat 8.5.0-16.0.2)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
```
MongoDBにアクセスするためのpymongoドライバーとデータ出力を整形するためのpprintモジュールをインポートし、pymongoからMongoClientをインポートします。
```
>>> import pymongo
>>> import pprint
>>> from pymongo import MongoClient
>>> 
```
MongoClientを使用して、Oracle Database 23c FreeにOracle Database API for MongoDB経由でアクセスします。
```
>>> client = MongoClient('mongodb://mongo_test:MyPassword1!@localhost:27017/mongo_test?authMechanism=PLAIN&authSource=$external&ssl=true&tlsInsecure=true&retryWrites=false&loadBalanced=true')
>>>
```
データベースを取得します。
```
>>> db = client.mongo_test
>>>
```
コレクションの一覧を取得します。
```
>>> for collection_name in db.list_collection_names():
...   print(collection_name)
... 
driver_dv
race_dv
team_dv
>>>
```
SODAを有効にしたJSON Relational Duality Viewがコレクションとして表示されました。

find()メソッドを使用して、各コレクションの内容を確認します。
```
>>> for driver in driver_dv.find():
...     pprint.pprint(driver)
... 
>>> team_dv = db.team_dv
>>> for team in team_dv.find():
...     pprint.pprint(team)
... 
>>> driver_dv = db.driver_dv
>>> for driver in driver_dv.find():
...     pprint.pprint(driver)
... 
>>> race_dv = db.race_dv
>>> for race in race_dv.find():
...     pprint.pprint(race)
... 
>>>
```
この時点では、どのコレクションにもデータはまだ入っていません。

# 3. JSON-Relational Duality Viewをコレクションとして操作する

insert_one()メソッドを使用して、コレクションteam_dvに２名のドライバー情報を含むドキュメントを追加してみます。
```
>>> team =   {
...     "_id": 2,
...     "name": "Mercedes",
...     "points": 0,
...     "driver": [
...       {
...         "driverId": 105,
...         "name": "George Russell",
...         "points": 0
...       },
...       {
...         "driverId": 106,
...         "name": "Lewis Hamilton",
...         "points": 0
...       }
...     ]
...   }
>>> insert_one_team_result = team_dv.insert_one(team)
>>> insert_one_team_result.inserted_id
2
>>>
```
コレクションteam_dvの内容を確認してみます。
```
>>> for team in team_dv.find():
...   pprint.pprint(team)
... 
{'_id': 2.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7^\xc5',
               'etag': b'S`\x01\xf3\x1a\x87\x18\x81\x9a\xee\xf2\x8e\xc2\r\x86w'},
 'driver': [{'driverId': 105.0, 'name': 'George Russell', 'points': 0.0},
            {'driverId': 106.0, 'name': 'Lewis Hamilton', 'points': 0.0}],
 'name': 'Mercedes',
 'points': 0.0}
>>>
```
先ほど追加したドキュメントにメタデータ（etag、asof）が付加されて格納されていることが確認できました。

コレクションdriver_dvの内容を確認してみます。
```
>>> for driver in driver_dv.find():
...   pprint.pprint(driver)
... 
{'_id': 105.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7^\xcb',
               'etag': b'\xa8\xbb\x18%\xf6!\x8e\xc0\xd3\x00g\x11sT\x05\x97'},
 'name': 'George Russell',
 'points': 0.0,
 'race': [],
 'team': 'Mercedes',
 'teamId': 2.0}
{'_id': 106.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7^\xcb',
               'etag': b'\xd3\xff2\x13y>0b\x04\xbb^P`6\x8eA'},
 'name': 'Lewis Hamilton',
 'points': 0.0,
 'race': [],
 'team': 'Mercedes',
 'teamId': 2.0}
>>>
```
コレクションteam_dvにドキュメントを追加することによって、ドキュメント内のドライバーの情報がコレクションdriver_dvに追加されることが確認できました。

SQL*Plusからmongo_testユーザとしてOracle Databse 23c Freeに接続し、Duality Viewのベースとなっているリレーショナル表の内容を確認してみます。

```
SQL> col name for a30
SQL> SELECT * FROM team;

   TEAM_ID NAME 			                  POINTS
---------- ------------------------------ ----------
	     2 Mercedes				                   0

SQL> SELECT * FROM driver;

 DRIVER_ID NAME 			                  POINTS	TEAM_ID
---------- ------------------------------ ---------- ----------
       105 George Russell			               0	      2
       106 Lewis Hamilton			               0	      2

SQL> SELECT * FROM race;

no rows selected

SQL> SELECT * FROM driver_race_map;

no rows selected

SQL>
```
コレクションteam_dvにドキュメントを1つ追加したことによって、team表に1レコード、driver表に2レコード追加されたことが確認できました。

次に、insert_many(）メソッドを使用して、コレクションteam_dvに複数のドキュメントを追加してみます。
```
>>> teams = [
...     {
...       "_id": 301,
...       "name": "Red Bull",
...       "points": 0,
...       "driver": [
...         {
...           "driverId": 101,
...           "name": "Max Verstappen",
...           "points": 0
...         },
...         {
...           "driverId": 102,
...           "name": "Sergio Perez",
...           "points": 0
...         }
...       ]
...     },
...     {
...       "_id": 302,
...       "name": "Ferrari",
...       "points": 0,
...       "driver": [
...         {
...           "driverId": 103,
...           "name": "Charles Leclerc",
...           "points": 0
...         },
...         {
...           "driverId": 104,
...           "name": "Carlos Sainz Jr",
...           "points": 0
...         }
...       ]
...     }
...   ]
>>> insert_many_teams_result = team_dv.insert_many(teams)
>>> insert_many_teams_result.inserted_ids
[301, 302]
>>> 
```
コレクションteam_dvの内容を確認してみます。
```
>>> for team in team_dv.find():
...   pprint.pprint(team)
... 
{'_id': 2.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7_N',
               'etag': b'S`\x01\xf3\x1a\x87\x18\x81\x9a\xee\xf2\x8e\xc2\r\x86w'},
 'driver': [{'driverId': 105.0, 'name': 'George Russell', 'points': 0.0},
            {'driverId': 106.0, 'name': 'Lewis Hamilton', 'points': 0.0}],
 'name': 'Mercedes',
 'points': 0.0}
{'_id': 301.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7_N',
               'etag': b'\x9f\x0f\x85Z9\xf4\xae\x8f\xec\xd7\xe6\xa1#\x85_\xd1'},
 'driver': [{'driverId': 101.0, 'name': 'Max Verstappen', 'points': 0.0},
            {'driverId': 102.0, 'name': 'Sergio Perez', 'points': 0.0}],
 'name': 'Red Bull',
 'points': 0.0}
{'_id': 302.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7_N',
               'etag': b'{bi\x9f\xec\xec\xff9!C\xbaz3^^G'},
 'driver': [{'driverId': 103.0, 'name': 'Charles Leclerc', 'points': 0.0},
            {'driverId': 104.0, 'name': 'Carlos Sainz Jr', 'points': 0.0}],
 'name': 'Ferrari',
 'points': 0.0}
>>>
```
insert_many()メソッドを使用して追加したドキュメントにメタデータが付与されて格納されていることが確認できました。

コレクションdriver_dvの内容を確認してみます。
```
>>> for driver in driver_dv.find():
...   pprint.pprint(driver)
... 
{'_id': 105.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7_[',
               'etag': b'\xa8\xbb\x18%\xf6!\x8e\xc0\xd3\x00g\x11sT\x05\x97'},
 'name': 'George Russell',
 'points': 0.0,
 'race': [],
 'team': 'Mercedes',
 'teamId': 2.0}
{'_id': 106.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7_[',
               'etag': b'\xd3\xff2\x13y>0b\x04\xbb^P`6\x8eA'},
 'name': 'Lewis Hamilton',
 'points': 0.0,
 'race': [],
 'team': 'Mercedes',
 'teamId': 2.0}
{'_id': 101.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7_[',
               'etag': b'\xf9\xd9\x81]\xff\'\x87\x9fa8l\xfd\x16"\xb0e'},
 'name': 'Max Verstappen',
 'points': 0.0,
 'race': [],
 'team': 'Red Bull',
 'teamId': 301.0}
{'_id': 102.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7_[',
               'etag': b'\x98e\xa2\x9d\xee_WTgJ\x9b\x1d.\xc5\x870'},
 'name': 'Sergio Perez',
 'points': 0.0,
 'race': [],
 'team': 'Red Bull',
 'teamId': 301.0}
{'_id': 103.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7_[',
               'etag': b'\xc4z\x91\xf5{\xf3\xcfE\xf0\xd8(B@9\x9a\x90'},
 'name': 'Charles Leclerc',
 'points': 0.0,
 'race': [],
 'team': 'Ferrari',
 'teamId': 302.0}
{'_id': 104.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7_[',
               'etag': b'6>\xc6\xbb\xf0\xfa\xdd\x91;!\x94\x82\x95\x9d\xa3\x9d'},
 'name': 'Carlos Sainz Jr',
 'points': 0.0,
 'race': [],
 'team': 'Ferrari',
 'teamId': 302.0}
>>> 
```
insert_many()メソッドを使用してコレクションteam_dvにドライバー情報を含むドキュメントを追加したことによって、ドキュメントに含まれるドライバーの情報がコレクションdriver_dvに追加されたことが確認できました。

Duality Viewのベースとなっているリレーショナル表の内容を確認してみます。
```
SQL> set linesize 200
SQL> col name for a30
SQL> SELECT * FROM team;

   TEAM_ID NAME 			                  POINTS
---------- ------------------------------ ----------
	     2 Mercedes				                   0
       301 Red Bull				                   0
       302 Ferrari				                   0

SQL> SELECT * FROM driver;

 DRIVER_ID NAME 			                  POINTS	TEAM_ID
---------- ------------------------------ ---------- ----------
       105 George Russell			               0	      2
       106 Lewis Hamilton			               0	      2
       101 Max Verstappen			               0	    301
       102 Sergio Perez 			               0	    301
       103 Charles Leclerc			               0	    302
       104 Carlos Sainz Jr			               0	    302

6 rows selected.

SQL> SELECT * FROM race;

no rows selected

SQL> SELECT * FROM driver_race_map;

no rows selected

SQL>
```
コレクションteam_dvにドキュメントを2つ追加したことによって、team表に2レコード、driver表に4レコード追加されたことがわかりました。

insert_many()メソッドを使用して、コレクションrace_dvに3つのドキュメントを追加します。
```
>>> races = [
...     {
...       "_id": 201,
...       "name": "Bahrain Grand Prix",
...       "laps": 57,
...       "date": "2022-03-20T00:00:00",
...       "podium": {}
...     },
...     {
...       "_id": 202,
...       "name": "Saudi Arabian Grand Prix",
...       "laps": 50,
...       "date": "2022-03-27T00:00:00",
...       "podium": {}
...     },
...     {
...       "_id": 203,
...       "name": "Australian Grand Prix",
...       "laps": 58,
...       "date": "2022-04-09T00:00:00",
...       "podium": {}
...     }
...   ]
>>> insert_many_races_result = race_dv.insert_many(races)
>>> insert_many_races_result.inserted_ids
[201, 202, 203]
>>>
```
コレクションrace_dvの内容を確認します。
```
>>> for race in race_dv.find():
...   pprint.pprint(race)
... 
{'_id': 201.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7`@',
               'etag': b'.\x8d\xc0\x95C\xdd%\xdc}X\x8f\xb9sM\x96+'},
 'date': datetime.datetime(2022, 3, 20, 0, 0),
 'laps': 57.0,
 'name': 'Bahrain Grand Prix',
 'podium': {},
 'result': []}
{'_id': 202.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7`@',
               'etag': b'~\x05j\x84R\x12\xbf\xde\x19\xe0\xc0\xd0\xcdT\x9e\xa0'},
 'date': datetime.datetime(2022, 3, 27, 0, 0),
 'laps': 50.0,
 'name': 'Saudi Arabian Grand Prix',
 'podium': {},
 'result': []}
{'_id': 203.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7`@',
               'etag': b'\xean\x11\x94\xc0\x12\x97\x0c\xa0q\x16\xee'
                       b'\x1e\xf1g\xe8'},
 'date': datetime.datetime(2022, 4, 9, 0, 0),
 'laps': 58.0,
 'name': 'Australian Grand Prix',
 'podium': {},
 'result': []}
>>>
```
insert_many()メソッドを使用して追加したドキュメントにメタデータが付与されて格納されていることが確認できました。

Duality Viewのベースとなっているリレーショナル表の内容を確認してみます。
```
SQL> col name for a30
SQL> SELECT * FROM team;

   TEAM_ID NAME 			                  POINTS
---------- ------------------------------ ----------
	     2 Mercedes				                   0
       301 Red Bull				                   0
       302 Ferrari				                   0

SQL> SELECT * FROM driver;

 DRIVER_ID NAME 			                  POINTS	TEAM_ID
---------- ------------------------------ ---------- ----------
       105 George Russell			               0	      2
       106 Lewis Hamilton			               0	      2
       101 Max Verstappen			               0	    301
       102 Sergio Perez 			               0	    301
       103 Charles Leclerc			               0	    302
       104 Carlos Sainz Jr			               0	    302

6 rows selected.

SQL> SELECT * FROM race;

   RACE_ID NAME 				                LAPS RACE_DATE PODIUM
---------- ------------------------------ ---------- --------- --------------------------------------------------------------------------------
       201 Bahrain Grand Prix			          57 20-MAR-22 {}
       202 Saudi Arabian Grand Prix		          50 27-MAR-22 {}
       203 Australian Grand Prix		          58 09-APR-22 {}

SQL> SELECT * FROM driver_race_map;

no rows selected

SQL>
```
コレクションrace_dvにドキュメントを3つ追加したことによって、race表に3レコード追加されたことがわかりました。

replace_oneメソッドを使用して、コレクションrace_dv内にある_idの値が201のドキュメントを、result（レース結果）を含む内容に変更（置換）してみます。
```
>>> race =   {
...     "name": "Bahrain Grand Prix",
...     "laps": 57,
...     "date": "2022-03-20T00:00:00",
...     "podium": {
...       "winner": {
...         "name": "Charles Leclerc",
...         "time": "01:37:33.584"
...       },
...       "firstRunnerUp": {
...         "name": "Carlos Sainz Jr",
...         "time": "01:37:39.182"
...       },
...       "secondRunnerUp": {
...         "name": "Lewis Hamilton",
...         "time": "01:37:43.259"
...       }
...     },
...     "result": [
...       {
...         "driverRaceMapId": 3,
...         "position": 1,
...         "driverId": 103,
...         "name": "Charles Leclerc"
...       },
...       {
...         "driverRaceMapId": 4,
...         "position": 2,
...         "driverId": 104,
...         "name": "Carlos Sainz Jr"
...       },
...       {
...         "driverRaceMapId": 9,
...         "position": 3,
...         "driverId": 106,
...         "name": "Lewis Hamilton"
...       },
...       {
...         "driverRaceMapId": 10,
...         "position": 4,
...         "driverId": 105,
...         "name": "George Russell"
...       }
...     ],
...   }
>>> replace_one_race_result = race_dv.replace_one({"_id":201},race)
>>> replace_one_race_result.matched_count
1
>>> replace_one_race_result.modified_count
1
>>> replace_one_race_result.raw_result
{'n': 1, 'nModified': 1, 'ok': 1, 'updatedExisting': True}
>>> 
```
コレクションrace_dvの内容を確認します。
```
>>> for race in race_dv.find():
...     pprint.pprint(race)
... 
{'_id': 201.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7`\xd4',
               'etag': b' \xf7\xd9\xf0\xc6\x9a\xc5\xf9Y\xdc\xa8\x19\xf9\x11hH'},
 'date': datetime.datetime(2022, 3, 20, 0, 0),
 'laps': 57.0,
 'name': 'Bahrain Grand Prix',
 'podium': {'firstRunnerUp': {'name': 'Carlos Sainz Jr',
                              'time': '01:37:39.182'},
            'secondRunnerUp': {'name': 'Lewis Hamilton',
                               'time': '01:37:43.259'},
            'winner': {'name': 'Charles Leclerc', 'time': '01:37:33.584'}},
 'result': [{'driverId': 103.0,
             'driverRaceMapId': 3.0,
             'name': 'Charles Leclerc',
             'position': 1.0},
            {'driverId': 104.0,
             'driverRaceMapId': 4.0,
             'name': 'Carlos Sainz Jr',
             'position': 2.0},
            {'driverId': 106.0,
             'driverRaceMapId': 9.0,
             'name': 'Lewis Hamilton',
             'position': 3.0},
            {'driverId': 105.0,
             'driverRaceMapId': 10.0,
             'name': 'George Russell',
             'position': 4.0}]}
{'_id': 202.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7`\xd4',
               'etag': b'~\x05j\x84R\x12\xbf\xde\x19\xe0\xc0\xd0\xcdT\x9e\xa0'},
 'date': datetime.datetime(2022, 3, 27, 0, 0),
 'laps': 50.0,
 'name': 'Saudi Arabian Grand Prix',
 'podium': {},
 'result': []}
{'_id': 203.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7`\xd4',
               'etag': b'\xean\x11\x94\xc0\x12\x97\x0c\xa0q\x16\xee'
                       b'\x1e\xf1g\xe8'},
 'date': datetime.datetime(2022, 4, 9, 0, 0),
 'laps': 58.0,
 'name': 'Australian Grand Prix',
 'podium': {},
 'result': []}
>>> 
```
コレクションrace_dv内の_idの値が201のドキュメントが、レース結果を含む内容に変更（置換）されました。

コレクションteam_dvの内容を確認してみます。
```
>>> for team in team_dv.find():
...     pprint.pprint(team)
... 
{'_id': 2.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7`\xe7',
               'etag': b'\x85X@\xb9\x05\xc8\xca\xfa\x99\xfb\x9c\xbf'
                       b'\x819\x92\xe5'},
 'driver': [{'driverId': 105.0, 'name': 'George Russell', 'points': 12.0},
            {'driverId': 106.0, 'name': 'Lewis Hamilton', 'points': 15.0}],
 'name': 'Mercedes',
 'points': 27.0}
{'_id': 301.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7`\xe7',
               'etag': b'\x9f\x0f\x85Z9\xf4\xae\x8f\xec\xd7\xe6\xa1#\x85_\xd1'},
 'driver': [{'driverId': 101.0, 'name': 'Max Verstappen', 'points': 0.0},
            {'driverId': 102.0, 'name': 'Sergio Perez', 'points': 0.0}],
 'name': 'Red Bull',
 'points': 0.0}
{'_id': 302.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7`\xe7',
               'etag': b'\xc5\xdd0\xf0M\xa1\xa6\xa3\x90\xbf\xab\x12'
                       b'\xb7\xd4\xf7\x00'},
 'driver': [{'driverId': 103.0, 'name': 'Charles Leclerc', 'points': 25.0},
            {'driverId': 104.0, 'name': 'Carlos Sainz Jr', 'points': 18.0}],
 'name': 'Ferrari',
 'points': 43.0}
>>> 
```
コレクションrace_dv内のドキュメントをレース結果を含む内容に変更したことによって、コレクションteam_dv内の各ドキュメントのpointsおよび各ドライバーのpoints（driver.points）が更新されていることが確認できました。

コレクションdriver_dvの内容を確認してみます。
```
>>> for driver in driver_dv.find():
...     pprint.pprint(driver)
... 
{'_id': 105.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7`\xf5',
               'etag': b".g\xa3\xa7R\xd7Pi'WH\x0bd\x85!\xb7"},
 'name': 'George Russell',
 'points': 12.0,
 'race': [{'driverRaceMapId': 10.0,
           'finalPosition': 4.0,
           'name': 'Bahrain Grand Prix',
           'raceId': 201.0}],
 'team': 'Mercedes',
 'teamId': 2.0}
{'_id': 106.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7`\xf5',
               'etag': b'Fo&v\x91m\x9d\xb3\xb0\xb3\\\x87\x19-\xa2\xaf'},
 'name': 'Lewis Hamilton',
 'points': 15.0,
 'race': [{'driverRaceMapId': 9.0,
           'finalPosition': 3.0,
           'name': 'Bahrain Grand Prix',
           'raceId': 201.0}],
 'team': 'Mercedes',
 'teamId': 2.0}
{'_id': 101.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7`\xf5',
               'etag': b'\xf9\xd9\x81]\xff\'\x87\x9fa8l\xfd\x16"\xb0e'},
 'name': 'Max Verstappen',
 'points': 0.0,
 'race': [],
 'team': 'Red Bull',
 'teamId': 301.0}
{'_id': 102.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7`\xf5',
               'etag': b'\x98e\xa2\x9d\xee_WTgJ\x9b\x1d.\xc5\x870'},
 'name': 'Sergio Perez',
 'points': 0.0,
 'race': [],
 'team': 'Red Bull',
 'teamId': 301.0}
{'_id': 103.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7`\xf5',
               'etag': b'^\xc1\xd8ga2\x0f\x1dy\xe3\xc8\xe0\x99\\\xf6r'},
 'name': 'Charles Leclerc',
 'points': 25.0,
 'race': [{'driverRaceMapId': 3.0,
           'finalPosition': 1.0,
           'name': 'Bahrain Grand Prix',
           'raceId': 201.0}],
 'team': 'Ferrari',
 'teamId': 302.0}
{'_id': 104.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7`\xf5',
               'etag': b'\x1az \xf9\x8f\x84\x17`\xfe\xcd\xcdC&Z<\xef'},
 'name': 'Carlos Sainz Jr',
 'points': 18.0,
 'race': [{'driverRaceMapId': 4.0,
           'finalPosition': 2.0,
           'name': 'Bahrain Grand Prix',
           'raceId': 201.0}],
 'team': 'Ferrari',
 'teamId': 302.0}
>>> 
```
コレクションrace_dv内のドキュメントをレース結果を含む内容に変更したことによって、コレクションdriver_dv内の各ドキュメントのpointsおよびraceの値が更新されていることが確認できました。

Duality Viewのベースとなっているリレーショナル表の内容を確認してみます。
```
SQL> SELECT * FROM race;

   RACE_ID NAME 				                LAPS RACE_DATE PODIUM
---------- ------------------------------ ---------- --------- --------------------------------------------------------------------------------
       201 Bahrain Grand Prix			          57 20-MAR-22 {"winner":{"name":"Charles Leclerc","time":"01:37:33.584"},"firstRunnerUp":{"name":"Carlos Sainz Jr","time":"01:37:39.182"},"secondRunnerUp":{"name":"Lewis Hamilton","time":"01:37:43.259"}}
       202 Saudi Arabian Grand Prix		          50 27-MAR-22 {}
       203 Australian Grand Prix		          58 09-APR-22 {}

SQL> SELECT * FROM driver_race_map;

DRIVER_RACE_MAP_ID    RACE_ID  DRIVER_ID   POSITION
------------------ ---------- ---------- ----------
		         3	      201	     103	      1
		         4	      201	     104	      2
		         9	      201	     106	      3
		        10	      201	     105	      4

SQL> SELECT * FROM team;

   TEAM_ID NAME 			                  POINTS
---------- ------------------------------ ----------
	     2 Mercedes				                  27
       301 Red Bull				                   0
       302 Ferrari				                  43

SQL> SELECT * FROM driver;

 DRIVER_ID NAME 			                  POINTS	TEAM_ID
---------- ------------------------------ ---------- ----------
       105 George Russell			              12	      2
       106 Lewis Hamilton			              15	      2
       101 Max Verstappen			               0	    301
       102 Sergio Perez 			               0	    301
       103 Charles Leclerc			              25	    302
       104 Carlos Sainz Jr			              18	    302

6 rows selected.

SQL> 
```
コレクションrace_dv内のドキュメントをレース結果を含む内容に変更したことによって、以下の変更があったことがわかりました。
・race表のpodium列の値が更新された
・driver_race_map表に行が追加された
・team表のpoints列の値が更新された
・driver表のpoints列の値が更新された

team表およびdriver表のpoints列の値が更新されたのは、1.で作成したトリガーdriver_race_map_triggerによるものです。
トリガーdriver_race_map_triggerによってteam表およびdriver表のpoints列の値が更新され、コレクションteam_dvのpoints、およびコレクションdriver_dvのdriver.pointsの値に反映されています。

updateOne()メソッドを使用して、コレクションrace_dv内にあるドキュメントのうち、nameの値が"Bahrain Grand Prix"であるドキュメントのnameの値を"Blue Air Bahrain Grand Prix"に変更してみます。
```
>>> update_one_race_result = race_dv.update_one({"name" : "Bahrain Grand Prix"}, {"$set" : {"name" : "Blue Air Bahrain Grand Prix"}})
>>> update_one_race_result.matched_count
1
>>> update_one_race_result.modified_count
1
>>> update_one_race_result.raw_result
{'n': 1, 'nModified': 1, 'ok': 1, 'updatedExisting': True}
>>> 
```
コレクションrace_dvの内容を確認してみます。
```
>>> for race in race_dv.find():
...   pprint.pprint(race)
... 
{'_id': 201.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7a$',
               'etag': b'\xf6\x90j\x8fz\x13\x1c\x12\x7f\xae\xf3,\xa4:\xf9z'},
 'date': datetime.datetime(2022, 3, 20, 0, 0),
 'laps': 57.0,
 'name': 'Blue Air Bahrain Grand Prix',
 'podium': {'firstRunnerUp': {'name': 'Carlos Sainz Jr',
                              'time': '01:37:39.182'},
            'secondRunnerUp': {'name': 'Lewis Hamilton',
                               'time': '01:37:43.259'},
            'winner': {'name': 'Charles Leclerc', 'time': '01:37:33.584'}},
 'result': [{'driverId': 103.0,
             'driverRaceMapId': 3.0,
             'name': 'Charles Leclerc',
             'position': 1.0},
            {'driverId': 104.0,
             'driverRaceMapId': 4.0,
             'name': 'Carlos Sainz Jr',
             'position': 2.0},
            {'driverId': 106.0,
             'driverRaceMapId': 9.0,
             'name': 'Lewis Hamilton',
             'position': 3.0},
            {'driverId': 105.0,
             'driverRaceMapId': 10.0,
             'name': 'George Russell',
             'position': 4.0}]}
{'_id': 202.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7a$',
               'etag': b'~\x05j\x84R\x12\xbf\xde\x19\xe0\xc0\xd0\xcdT\x9e\xa0'},
 'date': datetime.datetime(2022, 3, 27, 0, 0),
 'laps': 50.0,
 'name': 'Saudi Arabian Grand Prix',
 'podium': {},
 'result': []}
{'_id': 203.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7a$',
               'etag': b'\xean\x11\x94\xc0\x12\x97\x0c\xa0q\x16\xee'
                       b'\x1e\xf1g\xe8'},
 'date': datetime.datetime(2022, 4, 9, 0, 0),
 'laps': 58.0,
 'name': 'Australian Grand Prix',
 'podium': {},
 'result': []}
>>> 
```
コレクションrace_dv内のドキュメントのうち、nameの値が"Bahrain Grand Prix"であるドキュメント（_idの値が201のドキュメント）のnameの値が"Blue Air Bahrain Grand Prix"に変更されました。

コレクションdriver_dvの内容を確認してみます
```
>>> for driver in driver_dv.find():
...     pprint.pprint(driver)
... 
{'_id': 105.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7aP',
               'etag': b'\x13\xf8\xdc\x14\xf9 _\xce\x16\xb7\xe9\x11\xc3kc2'},
 'name': 'George Russell',
 'points': 12.0,
 'race': [{'driverRaceMapId': 10.0,
           'finalPosition': 4.0,
           'name': 'Blue Air Bahrain Grand Prix',
           'raceId': 201.0}],
 'team': 'Mercedes',
 'teamId': 2.0}
{'_id': 106.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7aP',
               'etag': b'n\xa0\xaa\x1f\xa6\xd8\x99lD\xb3u\xd0\xfbe\xe5\xf5'},
 'name': 'Lewis Hamilton',
 'points': 15.0,
 'race': [{'driverRaceMapId': 9.0,
           'finalPosition': 3.0,
           'name': 'Blue Air Bahrain Grand Prix',
           'raceId': 201.0}],
 'team': 'Mercedes',
 'teamId': 2.0}
{'_id': 101.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7aP',
               'etag': b'\xf9\xd9\x81]\xff\'\x87\x9fa8l\xfd\x16"\xb0e'},
 'name': 'Max Verstappen',
 'points': 0.0,
 'race': [],
 'team': 'Red Bull',
 'teamId': 301.0}
{'_id': 102.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7aP',
               'etag': b'\x98e\xa2\x9d\xee_WTgJ\x9b\x1d.\xc5\x870'},
 'name': 'Sergio Perez',
 'points': 0.0,
 'race': [],
 'team': 'Red Bull',
 'teamId': 301.0}
{'_id': 103.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7aP',
               'etag': b'\xd4D\x02\xd6\xa4\xa1\x83q\x86A\x99&8N\x1dG'},
 'name': 'Charles Leclerc',
 'points': 25.0,
 'race': [{'driverRaceMapId': 3.0,
           'finalPosition': 1.0,
           'name': 'Blue Air Bahrain Grand Prix',
           'raceId': 201.0}],
 'team': 'Ferrari',
 'teamId': 302.0}
{'_id': 104.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7aP',
               'etag': b'\xdf\x16\x11=A-\xb3\x9aLE]\xc9\xf1T=\xc9'},
 'name': 'Carlos Sainz Jr',
 'points': 18.0,
 'race': [{'driverRaceMapId': 4.0,
           'finalPosition': 2.0,
           'name': 'Blue Air Bahrain Grand Prix',
           'raceId': 201.0}],
 'team': 'Ferrari',
 'teamId': 302.0}
>>> 
```
コレクションrace_dv内にあるドキュメントのnameの値を変更することによって、コレクションdriver_dv内にある各ドキュメントのレース名（race.name）の値が更新されていることが確認できました。

コレクションteam_dvの内容を確認してみます。
```
>>> for team in team_dv.find():
...     pprint.pprint(team)
... 
{'_id': 2.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7a1',
               'etag': b'\x85X@\xb9\x05\xc8\xca\xfa\x99\xfb\x9c\xbf'
                       b'\x819\x92\xe5'},
 'driver': [{'driverId': 105.0, 'name': 'George Russell', 'points': 12.0},
            {'driverId': 106.0, 'name': 'Lewis Hamilton', 'points': 15.0}],
 'name': 'Mercedes',
 'points': 27.0}
{'_id': 301.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7a1',
               'etag': b'\x9f\x0f\x85Z9\xf4\xae\x8f\xec\xd7\xe6\xa1#\x85_\xd1'},
 'driver': [{'driverId': 101.0, 'name': 'Max Verstappen', 'points': 0.0},
            {'driverId': 102.0, 'name': 'Sergio Perez', 'points': 0.0}],
 'name': 'Red Bull',
 'points': 0.0}
{'_id': 302.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7a1',
               'etag': b'\xc5\xdd0\xf0M\xa1\xa6\xa3\x90\xbf\xab\x12'
                       b'\xb7\xd4\xf7\x00'},
 'driver': [{'driverId': 103.0, 'name': 'Charles Leclerc', 'points': 25.0},
            {'driverId': 104.0, 'name': 'Carlos Sainz Jr', 'points': 18.0}],
 'name': 'Ferrari',
 'points': 43.0}
>>>
```
コレクションteam_dv内のドキュメントにはレース名に関する情報が無いため、変更されていません。

Duality Viewのベースとなっているリレーショナル表の内容を確認してみます。
```
SQL> SELECT * FROM team;

   TEAM_ID NAME 			                  POINTS
---------- ------------------------------ ----------
	     2 Mercedes				                  27
       301 Red Bull				                   0
       302 Ferrari				                  43

SQL> SELECT * FROM driver;

 DRIVER_ID NAME 			                  POINTS	TEAM_ID
---------- ------------------------------ ---------- ----------
       105 George Russell			              12	      2
       106 Lewis Hamilton			              15	      2
       101 Max Verstappen			               0	    301
       102 Sergio Perez 			               0	    301
       103 Charles Leclerc			              25	    302
       104 Carlos Sainz Jr			              18	    302

6 rows selected.

SQL> SELECT * FROM race;

   RACE_ID NAME 				                LAPS RACE_DATE PODIUM
---------- ------------------------------ ---------- --------- --------------------------------------------------------------------------------
       201 Blue Air Bahrain Grand Prix		      57 20-MAR-22 {"winner":{"name":"Charles Leclerc","time":"01:37:33.584"},"firstRunnerUp":{"name":"Carlos Sainz Jr","time":"01:37:39.182"},"secondRunnerUp":{"name":"Lewis Hamilton","time":"01:37:43.259"}}
       202 Saudi Arabian Grand Prix		          50 27-MAR-22 {}
       203 Australian Grand Prix		          58 09-APR-22 {}

SQL> SELECT * FROM driver_race_map;

DRIVER_RACE_MAP_ID    RACE_ID  DRIVER_ID   POSITION
------------------ ---------- ---------- ----------
		         3	      201	     103	      1
		         4	      201	     104	      2
		         9	      201	     106	      3
		        10	      201	     105	      4

SQL> 
```
コレクションrace_dv内のドキュメントのnameの値を更新したことよって、race表のname列の値が変更されたことがわかりました。

update_one()メソッドを使用して、コレクションdriver_dv内にある_idの値が102のドキュメントのteamの値を'Ferrari'に変更してみます。
```
>>> update_one_driver_result = driver_dv.update_one({"_id" : 102} , {"$set" : {"team" : "Ferrari"}})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib64/python3.6/site-packages/pymongo/collection.py", line 1018, in update_one
    comment=comment,
  File "/usr/local/lib64/python3.6/site-packages/pymongo/collection.py", line 816, in _update_retryable
    (write_concern or self.write_concern).acknowledged and not multi, _update, session
  File "/usr/local/lib64/python3.6/site-packages/pymongo/mongo_client.py", line 1399, in _retryable_write
    return self._retry_with_session(retryable, func, s, None)
  File "/usr/local/lib64/python3.6/site-packages/pymongo/mongo_client.py", line 1286, in _retry_with_session
    return self._retry_internal(retryable, func, session, bulk)
  File "/usr/local/lib64/python3.6/site-packages/pymongo/mongo_client.py", line 1320, in _retry_internal
    return func(session, sock_info, retryable)
  File "/usr/local/lib64/python3.6/site-packages/pymongo/collection.py", line 812, in _update
    comment=comment,
  File "/usr/local/lib64/python3.6/site-packages/pymongo/collection.py", line 761, in _update
    _check_write_command_response(result)
  File "/usr/local/lib64/python3.6/site-packages/pymongo/helpers.py", line 216, in _check_write_command_response
    _raise_last_write_error(write_errors)
  File "/usr/local/lib64/python3.6/site-packages/pymongo/helpers.py", line 189, in _raise_last_write_error
    raise WriteError(error.get("errmsg"), error.get("code"), error)
pymongo.errors.WriteError: ORA-40940: Cannot update field 'team' corresponding to column 'NAME' of table 'TEAM' in JSON Relational Duality View 'DRIVER_DV': Missing UPDATE annotation or NOUPDATE annotation specified.
, full error: {'index': 0, 'errmsg': "ORA-40940: Cannot update field 'team' corresponding to column 'NAME' of table 'TEAM' in JSON Relational Duality View 'DRIVER_DV': Missing UPDATE annotation or NOUPDATE annotation specified.\n", 'code': -1}
>>>
```
エラーが発生してコレクションdriver_dv内のteamの値を変更できませんでした。
これはdriver_dvのDDLの8行目でNOUPDATEが指定されているためです。
```
SQL> CREATE OR REPLACE JSON RELATIONAL DUALITY VIEW driver_dv AS
  2    SELECT JSON {'_id' IS d.driver_id,
  3                 'name'     IS d.name,
  4                 'points'   IS d.points,
  5                 UNNEST
  6                   (SELECT JSON {'teamId' IS t.team_id,
  7                                 'team'   IS t.name WITH NOCHECK}
  8                      FROM team t WITH NOINSERT NOUPDATE NODELETE -- ※この部分
  9                      WHERE t.team_id = d.team_id),
 10                 'race'     IS
 11                   [ SELECT JSON {'driverRaceMapId' IS drm.driver_race_map_id,
 12                                  UNNEST
 13                                    (SELECT JSON {'raceId' IS r.race_id,
 14                                                  'name'   IS r.name}
 15                                       FROM race r WITH NOINSERT NOUPDATE NODELETE
 16                                       WHERE r.race_id = drm.race_id),
 17                                  'finalPosition'   IS drm.position}
 18                  FROM driver_race_map drm WITH INSERT UPDATE NODELETE
 19                  WHERE drm.driver_id = d.driver_id ]}
 20      FROM driver d WITH INSERT UPDATE DELETE;
```
delete_one()メソッドを使用して、コレクションrace_dv内にある_idの値が203のドキュメントを削除してみます。
```
>>> delete_one_race_result = race_dv.delete_one({"_id":203})
>>> delete_one_race_result.raw_result
{'n': 1, 'ok': 1}
>>>
```
コレクションrace_dvの内容を確認してみます。
```
>>> for race in race_dv.find():
...   pprint.pprint(race)
... 
{'_id': 201.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7co',
               'etag': b'\xf6\x90j\x8fz\x13\x1c\x12\x7f\xae\xf3,\xa4:\xf9z'},
 'date': datetime.datetime(2022, 3, 20, 0, 0),
 'laps': 57.0,
 'name': 'Blue Air Bahrain Grand Prix',
 'podium': {'firstRunnerUp': {'name': 'Carlos Sainz Jr',
                              'time': '01:37:39.182'},
            'secondRunnerUp': {'name': 'Lewis Hamilton',
                               'time': '01:37:43.259'},
            'winner': {'name': 'Charles Leclerc', 'time': '01:37:33.584'}},
 'result': [{'driverId': 103.0,
             'driverRaceMapId': 3.0,
             'name': 'Charles Leclerc',
             'position': 1.0},
            {'driverId': 104.0,
             'driverRaceMapId': 4.0,
             'name': 'Carlos Sainz Jr',
             'position': 2.0},
            {'driverId': 106.0,
             'driverRaceMapId': 9.0,
             'name': 'Lewis Hamilton',
             'position': 3.0},
            {'driverId': 105.0,
             'driverRaceMapId': 10.0,
             'name': 'George Russell',
             'position': 4.0}]}
{'_id': 202.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7co',
               'etag': b'~\x05j\x84R\x12\xbf\xde\x19\xe0\xc0\xd0\xcdT\x9e\xa0'},
 'date': datetime.datetime(2022, 3, 27, 0, 0),
 'laps': 50.0,
 'name': 'Saudi Arabian Grand Prix',
 'podium': {},
 'result': []}
>>> 
```
コレクションrace_dv内にあった_idの値が203のドキュメントが削除されました。

Duality Viewのベースとなっているリレーショナル表の内容を確認してみます。
```
SQL> SELECT * FROM race;

   RACE_ID NAME 				                LAPS RACE_DATE PODIUM
---------- ------------------------------ ---------- --------- --------------------------------------------------------------------------------
       201 Bahrain Grand Prix			          57 20-MAR-22 {"winner":{"name":"Charles Leclerc","time":"01:37:33.584"},"firstRunnerUp":{"name":"Carlos Sainz Jr","time":"01:37:39.182"},"secondRunnerUp":{"name":"Lewis Hamilton","time":"01:37:43.259"}}
       202 Saudi Arabian Grand Prix		          50 27-MAR-22 {}

SQL> 
```
コレクションrace_dvから_idの値が202のドキュメントを削除したことによって、race表内のrace_idが202のレコードが削除されたことがわかりました。

コレクションteam_dvとdriver_dvの内容を確認してみます。
```
>>> for team in team_dv.find():
...     pprint.pprint(team)
... 
{'_id': 2.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7c\xa0',
               'etag': b'\x85X@\xb9\x05\xc8\xca\xfa\x99\xfb\x9c\xbf'
                       b'\x819\x92\xe5'},
 'driver': [{'driverId': 105.0, 'name': 'George Russell', 'points': 12.0},
            {'driverId': 106.0, 'name': 'Lewis Hamilton', 'points': 15.0}],
 'name': 'Mercedes',
 'points': 27.0}
{'_id': 301.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7c\xa0',
               'etag': b'\x9f\x0f\x85Z9\xf4\xae\x8f\xec\xd7\xe6\xa1#\x85_\xd1'},
 'driver': [{'driverId': 101.0, 'name': 'Max Verstappen', 'points': 0.0},
            {'driverId': 102.0, 'name': 'Sergio Perez', 'points': 0.0}],
 'name': 'Red Bull',
 'points': 0.0}
{'_id': 302.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7c\xa0',
               'etag': b'\xc5\xdd0\xf0M\xa1\xa6\xa3\x90\xbf\xab\x12'
                       b'\xb7\xd4\xf7\x00'},
 'driver': [{'driverId': 103.0, 'name': 'Charles Leclerc', 'points': 25.0},
            {'driverId': 104.0, 'name': 'Carlos Sainz Jr', 'points': 18.0}],
 'name': 'Ferrari',
 'points': 43.0}
>>> 
>>> for driver in driver_dv.find():
...     pprint.pprint(driver)
... 
{'_id': 105.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7c\xb3',
               'etag': b'\x13\xf8\xdc\x14\xf9 _\xce\x16\xb7\xe9\x11\xc3kc2'},
 'name': 'George Russell',
 'points': 12.0,
 'race': [{'driverRaceMapId': 10.0,
           'finalPosition': 4.0,
           'name': 'Blue Air Bahrain Grand Prix',
           'raceId': 201.0}],
 'team': 'Mercedes',
 'teamId': 2.0}
{'_id': 106.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7c\xb3',
               'etag': b'n\xa0\xaa\x1f\xa6\xd8\x99lD\xb3u\xd0\xfbe\xe5\xf5'},
 'name': 'Lewis Hamilton',
 'points': 15.0,
 'race': [{'driverRaceMapId': 9.0,
           'finalPosition': 3.0,
           'name': 'Blue Air Bahrain Grand Prix',
           'raceId': 201.0}],
 'team': 'Mercedes',
 'teamId': 2.0}
{'_id': 101.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7c\xb3',
               'etag': b'\xf9\xd9\x81]\xff\'\x87\x9fa8l\xfd\x16"\xb0e'},
 'name': 'Max Verstappen',
 'points': 0.0,
 'race': [],
 'team': 'Red Bull',
 'teamId': 301.0}
{'_id': 102.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7c\xb3',
               'etag': b'\x98e\xa2\x9d\xee_WTgJ\x9b\x1d.\xc5\x870'},
 'name': 'Sergio Perez',
 'points': 0.0,
 'race': [],
 'team': 'Red Bull',
 'teamId': 301.0}
{'_id': 103.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7c\xb3',
               'etag': b'\xd4D\x02\xd6\xa4\xa1\x83q\x86A\x99&8N\x1dG'},
 'name': 'Charles Leclerc',
 'points': 25.0,
 'race': [{'driverRaceMapId': 3.0,
           'finalPosition': 1.0,
           'name': 'Blue Air Bahrain Grand Prix',
           'raceId': 201.0}],
 'team': 'Ferrari',
 'teamId': 302.0}
{'_id': 104.0,
 '_metadata': {'asof': b'\x00\x00\x00\x00\x00\xd7c\xb3',
               'etag': b'\xdf\x16\x11=A-\xb3\x9aLE]\xc9\xf1T=\xc9'},
 'name': 'Carlos Sainz Jr',
 'points': 18.0,
 'race': [{'driverRaceMapId': 4.0,
           'finalPosition': 2.0,
           'name': 'Blue Air Bahrain Grand Prix',
           'raceId': 201.0}],
 'team': 'Ferrari',
 'teamId': 302.0}
>>> 
```
コレクションrace_dv内にあった_idの値が203のドキュメントにはレース結果が含まれていなかったため、コレクションteam_dv、driver_dvの内容は変更されませんでした。

delete_many()メソッドを使用して、コレクションrace_dvの全てのドキュメントを削除します。
```
>>> delete_many_races_result = race_dv.delete_many({})
>>> delete_many_races_result.raw_result
{'n': 2, 'ok': 1}
>>>
```
コレクションrace_dvの内容を確認してみます。
```
>>> for race in race_dv.find():
...   pprint.pprint(race)
... 
>>> 
```
コレクションrace_dvが空になったことが確認できました。

delete_many()メソッドを使用して、コレクションdriver_dvの全てのドキュメントを削除します。
```
>>> delete_many_driver_result = driver_dv.delete_many({})
>>> delete_many_driver_result.raw_result
{'n': 6, 'ok': 1}
>>>
```
コレクションdriver_dvの内容を確認してみます。
```
>>> for driver in driver_dv.find():
...     pprint.pprint(driver)
... 
>>>
```
コレクションdriver_dvが空になったことが確認できました。

delete_many()メソッドを使用して、コレクションteam_dvの全てのドキュメントを削除します。
```
>>> delete_many_team_result = team_dv.delete_many({})
>>> delete_many_team_result.raw_result
{'n': 3, 'ok': 1}
>>>
```
コレクションteam_dvの内容を確認してみます。
```
>>> for team in team_dv.find():
...     pprint.pprint(team)
... 
>>>
```
コレクションteam_dvが空になったことが確認できました。

# 4. Duality Viewのベースとなっている表の内容の確認
Duality Viewのベースとなっている各表のデータを確認してみます。
```
SQL> SELECT * FROM team;

no rows selected

SQL> SELECT * FROM driver;

no rows selected

SQL> SELECT * FROM race;

no rows selected

SQL> SELECT * FROM driver_race_map;

no rows selected

SQL> 
```
Duality Viewのベースとなっている各表の全てのデータが削除されていることが確認できました。

# 参考情報
・[PyMongo 4.3.3 documentation：mongo_client](https://pymongo.readthedocs.io/en/stable/api/pymongo/mongo_client.html)
・[PyMongo 4.3.3 documentation：collection – Collection level operations](https://pymongo.readthedocs.io/en/stable/api/pymongo/collection.html)
・[PyMongo 4.3.3 documentation：results – Result class definitions](https://pymongo.readthedocs.io/en/stable/api/pymongo/results.html#pymongo.results.UpdateResult)
・[Python Documentation：pprint](https://docs.python.org/ja/3/library/pprint.html)