Autonomous Database 23ai：MongoDB ShellからMongoDB API経由でAutonomous Databaseにアクセスして色々試してみた

# はじめに

東京リージョンのAutonomous Database Serverlessで、Oracle Database 23aiが利用可能になりました。

Oracle Database 23aiには、JSONコレクション表という MongoDBとの互換性向上のための新しい機能が追加されています。

JSONコレクション表は、以下のような特徴があります。
・dataという名前のJSONデータ型の列のみを持つ
・ドキュメント識別子フィールド_idを持たないJSONドキュメントを追加すると、自動的にドキュメント識別子フィールド_idが自動生成されたドキュメント識別子と共にドキュメントに追加される

そこで今回は、Autonomous Database 23aiのOracle Database API for MongoDBを有効化し、MongoDB ShellからAutonomous Databaseにアクセスして、コレクションの作成やコレクション内のドキュメントの操作を試してみました。


# 1.Oracle Database API for MongoDBの有効化

OCIコンソールのAutonomous databaseの詳細画面から「ツール構成」にアクセスします。
![スクリーンショット 2024-07-09 17.53.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/94053e4b-f286-53c2-4493-9a3aa37ae8fd.png)
「ツール構成の編集」をクリックします。
![スクリーンショット 2024-07-09 17.56.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/918c941c-e51e-0b50-c75a-68d3db57abb0.png)
「MongoDB API」のステータスを「有効」に変更します。
![スクリーンショット 2024-07-09 17.57.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/c59a01d1-2a39-8f30-4128-a3dde0dfd38d.png)
「MongoDB API」のパブリック・アクセスURL（接続文字列）をコピーします。
![スクリーンショット 2024-07-09 17.55.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/2b34129f-ebba-a13b-25bf-e7ca7cf51eb0.png)

Autonomous DatabaseのMongoDB APIの接続文字列はこちらのような形式になっています。
```
mongodb://[user:password@]XXXXXXXXXXXXXXX-XXXXXXX.adb.ap-tokyo-1.oraclecloudapps.com:27017/[user]?authMechanism=PLAIN&authSource=$external&ssl=true&retryWrites=false&loadBalanced=true
```
「user」に接続先となるAutonomous DatabaseのDBユーザ名、「password」にそのパスワードを指定します。
例えば、ユーザ名がmongouser、パスワードがPassw0rdの場合は、
```
mongodb://mongouser:Passw0rd@]XXXXXXXXXXXXXXX-XXXXXXX.adb.ap-tokyo-1.oraclecloudapps.com:27017/Passw0rd?authMechanism=PLAIN&authSource=$external&ssl=true&retryWrites=false&loadBalanced=true
```
のような形になります。

# 2. SQLでJSONコレクション表を作成し、MongoDB Shellからコレクションとしてアクセスする

SQL*Plusから、adminユーザとして23aiのAutonomous Databseに接続します。
```
[oracle@oracle23ai ~]$ sqlplus  admin/************@adw23ai

SQL*Plus: Release 23.0.0.0.0 - Production on Tue Jul 9 17:46:26 2024
Version 23.4.0.24.05

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

Last Successful login time: Tue Jul 09 2024 17:20:42 +09:00

Connected to:
Oracle Database 23ai Enterprise Edition Release 23.0.0.0.0 - Production
Version 23.5.0.24.06

SQL> 
```

JSONコレクション表fruit_collectionを作成します。

```
SQL> CREATE JSON COLLECTION TABLE fruit_collection;

Table created.

SQL>
```

JSONコレクション表fruit_collectionの構造を確認してみます。

```
SQL> desc fruit_collection 
 Name					                   Null?    Type
 ----------------------------------------- -------- ----------------------------
 DATA						                        JSON

SQL> 
```
JSONコレクション表はJSONデータ型の列dataのみを持つ構造になっています。

ユーザが所有するJSONコレクションはuser_json_collectionsビューで確認できます。

```
SQL> col owner for a10
SQL> col collection_name for a20
SQL> SELECT * FROM user_json_collections;

OWNER	   COLLECTION_NAME	    COLLECTION_T
---------- -------------------- ------------
ADMIN	   FRUIT_COLLECTION	    TABLE

SQL>
```
fruit_collection表にJSONドキュメントを1件挿入します。
```
SQL> INSERT INTO fruit_collection VALUES ('{"name": "Apple","qty" : 10}');

1 row created.

SQL> COMMIT;

Commit complete.

SQL>
```
fruit_collection表の内容を確認します。
```
SQL> SELECT * FROM fruit_collection;

DATA
--------------------------------------------------------------------------------
{"_id":"668ced11f662595b3b4f8870","name":"Apple","qty":10}

SQL>
```
挿入したJSONドキュメントにドキュメント識別子フィールド_idが追加されていることがわかります。

adminユーザとして、MongoDB Shellから23aiのAutonomous Databseに接続します。
```
user@mymac ~ % mongosh 'mongodb://admin:************@XXXXXXXXXXXXXXX-ADW23AI.adb.ap-tokyo-1.oraclecloudapps.com:27017/admin?authMechanism=PLAIN&authSource=$external&ssl=true&retryWrites=false&loadBalanced=true'
Current Mongosh Log ID:	668ce63abd08fbb3dd77768a
Connecting to:		mongodb://<credentials>@XXXXXXXXXXXXXXX-ADW23AI.adb.ap-tokyo-1.oraclecloudapps.com:27017/admin?authMechanism=PLAIN&authSource=%24external&ssl=true&retryWrites=false&loadBalanced=true&tls=true&tlsAllowInvalidCertificates=true&appName=mongosh+2.2.10
Using MongoDB:		4.2.14
Using Mongosh:		2.2.10

For mongosh info see: https://docs.mongodb.com/mongodb-shell/

admin> 
```
コレクションの一覧を確認します。
```
admin> show collections
FRUIT_COLLECTION
admin>
```
SQL*Plusから作成したJSONコレクション表fruit_collectionが、コレクションとして表示されました。

fruit_collection内のデータを確認してみます。
```
admin> db.fruit_collection.find()
[
  { _id: ObjectId('668ced11f662595b3b4f8870'), name: 'Apple', qty: 10 }
]
admin> 
```
SQL*Plusで確認したデータと同じデータが表示されました。

insertOneメソッドで、fruit_collectionにJSONドキュメントを追加します。
```
admin> db.fruit_collection.insertOne({"name": "Orange","qty" : 20})
{
  acknowledged: true,
  insertedId: ObjectId('668cee46bd08fbb3dd77768b')
}
admin> 
```
fruit_collection内の内容を確認してみます。
```
admin> db.fruit_collection.find()
[
  {
    _id: ObjectId('668cee46bd08fbb3dd77768b'),
    name: 'Orange',
    qty: 20
  },
  { _id: ObjectId('668ced11f662595b3b4f8870'), name: 'Apple', qty: 10 }
]
admin> 
```
fruit_collectionにJSONドキュメントが追加されていることが確認できました。

SQL*Plusからfruit_collectionの内容を確認してみます。
```
SQL> SELECT * FROM fruit_collection;

DATA
--------------------------------------------------------------------------------
{"_id":"668cee46bd08fbb3dd77768b","name":"Orange","qty":20}
{"_id":"668ced11f662595b3b4f8870","name":"Apple","qty":10}

SQL>
```
SQL*Plus側でもMongoDB Shellから追加されたJSONドキュメントを確認できました。

次に、MongoDB Shellからfruit_collection内のJSONドキュメントを更新してみます。

```
admin> db.fruit_collection.updateOne(
...    { name: "Apple" },
...    {
...      $set: { qty: 40 }
...    }
... )
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}
admin>
```

fruit_collection内の内容を確認してみます。

```
admin> db.fruit_collection.find()
[
  {
    _id: ObjectId('668cee46bd08fbb3dd77768b'),
    name: 'Orange',
    qty: 20
  },
  { _id: ObjectId('668ced11f662595b3b4f8870'), name: 'Apple', qty: 40 }
]
admin> 
```

fruit_collection内のJSONドキュメントが更新されていることが確認できました。

SQL*Plusからfruit_collectionのデータを確認してみます。

```
SQL> SELECT * FROM fruit_collection;

DATA
--------------------------------------------------------------------------------
{"_id":"668cee46bd08fbb3dd77768b","name":"Orange","qty":20}
{"_id":"668ced11f662595b3b4f8870","name":"Apple","qty":40}

SQL>
```

SQL*Plus側でもMongoDB Shellから更新されたJSONドキュメントを確認できました。

MongoDB Shellからfruit_collection内のJSONドキュメントを削除してみます。

```
admin> db.fruit_collection.deleteOne( { name: "Apple" } )
{ acknowledged: true, deletedCount: 1 }
admin> 
```

fruit_collectionの内容を確認してみます。

```
admin> db.fruit_collection.find()
[
  {
    _id: ObjectId('668cee46bd08fbb3dd77768b'),
    name: 'Orange',
    qty: 20
  }
]
admin>
```

fruit_collection内のJSONドキュメントが削除されていることが確認できました。

SQL*Plusからfruit_collectionの内容を確認してみます。

```
SQL> SELECT * FROM fruit_collection;

DATA
--------------------------------------------------------------------------------
{"_id":"668cee46bd08fbb3dd77768b","name":"Orange","qty":20}

SQL> 
```

SQL*Plus側でもfruit_collectionからJSONドキュメントが削除されていることを確認できました。

MongoDB Shellからfruit_collectionを削除してみます。

```
admin> db.fruit_collection.drop()
true
admin>
```
show collectionsでコレクションfruit_collectionが削除されたことを確認します。
```
admin> show collections

admin> 
```
fruit_collectionが削除されたことが確認できました。

SQL*Plusからuser_json_collectionを確認してみます。

```
SQL> SELECT * FROM user_json_collections;

no rows selected

SQL> 
```

SQL*Plus側でもfruit_collectionが削除されていることを確認できました。

# 3.MongoDB Shellからコレクションを作成し、SQLからJSONコレクション表としてアクセスする

MongoDB Shellからdb.createCollection()メソッドでコレクションvegetable_collectionを作成します。

```
admin> db.createCollection('vegetable_collection')
{ ok: 1 }
admin>
```

show collectionsで作成したコレクションを確認します。

```
admin> show collections
vegetable_collection
admin>
```
コレクションvegetable_collectionが作成されたことが確認できました。

SQL*Plusからuser_json_collectionsの内容を確認します。

```
SQL> col owner for a10
SQL> col collection_name for a20
SQL> SELECT * FROM user_json_collections;

OWNER	   COLLECTION_NAME	    COLLECTION_T
---------- -------------------- ------------
ADMIN	   vegetable_collection TABLE

SQL>
```

JSONコレクション表vegetable_collectionが作成されていることが確認できました。

JSONコレクション表fruit_collectionの構造を確認してみます。

```
SQL> desc vegetable_collection
 Name					                   Null?    Type
 ----------------------------------------- -------- ----------------------------
 DATA						                        JSON

SQL> 
```

fruit_collectionと同様に、JSONコレクション表vegetable_collectionはJSONデータ型の列dataのみを持つ構造になっています。

MongoDB Shellから、insertOne()メソッドを使用してJSONドキュメントをvegetable_collectionに追加します。
```
admin> db.vegetable_collection.insertOne({"name": "Eggplant","qty" : 10})
{
  acknowledged: true,
  insertedId: ObjectId('668cf353bd08fbb3dd77768c')
}
admin>
```
SQL*Plusからvegetable_collectionの内容を確認してみます。

```
SQL> SELECT * FROM vegetable_collection;

DATA
--------------------------------------------------------------------------------
{"_id":"668cf353bd08fbb3dd77768c","name":"Eggplant","qty":10}

SQL>
```

SQL*Plus側でもMongoDB Shellから追加されたJSONドキュメントを確認できました。

SQL*Plusからvegetable_collectionにJSONドキュメントを追加します。

```
SQL> INSERT INTO vegetable_collection VALUES ('{"name": "Carrot","qty" : 30}');

1 row created.

SQL> COMMIT;

Commit complete.

SQL>
```

vegetable_collectionの内容を確認します。

```
SQL> SELECT * FROM vegetable_collection;

DATA
--------------------------------------------------------------------------------
{"_id":"668cf353bd08fbb3dd77768c","name":"Eggplant","qty":10}
{"_id":"668cf3cf58355731c64c6c7d","name":"Carrot","qty":30}

SQL>
```

vegetable_collectionにJSONドキュメントが追加されていることを確認できました。

MongoDB Shell側からvegetable_collectionの内容を確認してみます。

```
admin> db.vegetable_collection.find()
[
  {
    _id: ObjectId('668cf353bd08fbb3dd77768c'),
    name: 'Eggplant',
    qty: 10
  },
  {
    _id: ObjectId('668cf3cf58355731c64c6c7d'),
    name: 'Carrot',
    qty: 30
  }
]
admin>
```
MongoDB Shell側でもSQL*Plusから追加されたJSONドキュメントを確認できました。

次に、SQL*Plusからvegetable_collection内のJSONドキュメントを更新してみます。

```
SQL> UPDATE vegetable_collection v
  2  SET data = json_transform(data, SET '$.qty' = 20)
  3  WHERE v.data.name = 'Eggplant';

1 row updated.

SQL> COMMIT;

Commit complete.

SQL> 
```

vegetable_collection内の内容を確認してみます。

```
SQL> SELECT * FROM vegetable_collection;

DATA
--------------------------------------------------------------------------------
{"_id":"668cf353bd08fbb3dd77768c","name":"Eggplant","qty":20}
{"_id":"668cf3cf58355731c64c6c7d","name":"Carrot","qty":30}

SQL>
```

vegetable_collection内のJSONドキュメントが更新されていることが確認できました。

MongoDB Shellからvegetable_collectionの内容を確認してみます。

```
admin> db.vegetable_collection.find()
[
  {
    _id: ObjectId('668cf353bd08fbb3dd77768c'),
    name: 'Eggplant',
    qty: 20
  },
  {
    _id: ObjectId('668cf3cf58355731c64c6c7d'),
    name: 'Carrot',
    qty: 30
  }
]
admin> 
```

MongoDB Shell側でもSQL*Plusから更新されたJSONドキュメントを確認できました。

SQL*Plusからvegetable_collection内のJSONドキュメントを削除してみます。

```
SQL> DELETE FROM vegetable_collection v
  2  WHERE v.data.name = 'Eggplant';

1 row deleted.

SQL> COMMIT;

Commit complete.

SQL>
```

vegetable_collectionの内容を確認してみます。

```
SQL> SELECT * FROM vegetable_collection;

DATA
--------------------------------------------------------------------------------
{"_id":"668cf3cf58355731c64c6c7d","name":"Carrot","qty":30}

SQL>
```

vegetable_collection内のJSONドキュメントが更新されていることが確認できました。

MongoDB Shellからvegetable_collectionの内容を確認してみます。

```
admin> db.vegetable_collection.find()
[
  {
    _id: ObjectId('668cf3cf58355731c64c6c7d'),
    name: 'Carrot',
    qty: 30
  }
]
admin>
```

MongoDB Shell側でもJSONドキュメントが削除されていることを確認できました。

SQL*Plusからvegetable_collectionを削除してみます。

```
SQL> DROP TABLE vegetable_collection;
DROP TABLE vegetable_collection
           *
ERROR at line 1:
ORA-00942: table or view "ADMIN"."VEGETABLE_COLLECTION" does not exist
Help: https://docs.oracle.com/error-help/db/ora-00942/


SQL> 
```
DROP TABLE文で削除しようとするとエラーになりました。

**Oracle Database API for MongoDBから作成したコレクション（JSONコレクション表）は、コレクション名がケース・センシティブになっているため、表名をダブルクウォートで囲む必要があります。
（記事執筆時点の情報）**

表名をダブルクウォートで囲んで、再度実行してみます。
```
SQL> DROP TABLE "vegetable_collection";

Table dropped.

SQL>
```
vegetable_collectionが削除できました。

user_json_collectionsの内容を確認します。

```
SQL> SELECT * FROM user_json_collections;

no rows selected

SQL> 
```
vegetable_collectionが削除されたことが確認できました。

MongoDB Shellから、show collectionsでコレクションvegetable_collectionが削除されたことを確認してみます。
```
admin> show collections

admin>
```

コレクションvegetable_collectionが削除されていることが確認できました。

# まとめ

Oracle Database API for MongoDBを使用することで、あたかもMongoDBにアクセスしているかのように、MongoDB ShellからAutonomous Database 23aiに接続して、コレクションの操作が行えることがわかりました。

また、SQLインターフェースから作成したOracle Database 23ai内のJSONコレクション表は、MongoDB Shellからコレクションとしてシームレスにアクセス可能であることがわかりました。

さらに、MongoDB Shellから作成したコレクションは、Oracle Database 23ai内ではJSONコレクション表として作成され、SQLインターフェースからもシームレスにコレクション内のデータにアクセスできることがわかりました。


# 参考情報
・[Provision an Autonomous Database Instance](https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/adbsb/autonomous-provision.html)
・[Using Oracle Database API for MongoDB](https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/adbsb/mongo-using-oracle-database-api-mongodb.html)
・[JSON Collections](https://docs.oracle.com/en/database/oracle/oracle-database/23/nfcoa/json.html#GUID-101238-1)