Livelabs:AutoREST with JSON Relational Duality Views in 23aiの実施メモ

# はじめに

## この記事に書いてること

- LiveLabs：[AutoREST with JSON Relational Duality Views in 23ai](https://apexapps.oracle.com/pls/apex/r/dbpm/livelabs/view-workshop?wid=3977)のhandonの実施イメージ
- AutoREST、JSON Relational Duality Viewsについて、「アプリ観点で何ができるのか」の概要
- REST/JSON操作だけで、JSON Relational Duality Viewsを構成するテーブルにデータが想定どおり反映されること、RDB/正規化では一般的な「一箇所の更新で、アプリケーション全体で整合性、一貫性のある更新」が、JSONアプリケーションでも簡単に実現できること

## AutoRESTとは
- Oracle Autonomous Database（ADB）のAutoRESTは、データベース内のテーブルやビューを簡単にREST API化できる機能
- 主に以下の特長がある
  - ノーコードで簡単：特別なプログラムやコードを書かず、GUIで操作するだけでAPIを作れる
  - 迅速な開発：REST APIを使ったアプリケーション開発がスピードアップする
  - セキュリティ強化：Oracle Cloudが標準で提供するセキュリティ機能を利用できる
## JSON Relational Duality Viewsとは
- OracleのJSON Relational Duality Views（Duality Views） は、リレーショナルデータベースの表をJSONデータとして簡単に扱える機能
- 主に以下の特長がある
  - JSONでアプリを作りながらも、リレーショナルDBの強み（整合性、トランザクション管理）を維持できる
  - アプリケーション開発者はJSONの利便性を、データ管理者はRDBの堅牢性の両方を同時に満たしたデータ開発が可能
  - より具体的なメリット：
    - ① 開発効率の向上（ノーコードでJSON対応）
通常、JSONデータとリレーショナルDBを連携する場合、変換ロジック（ORMなど）を書く必要があります。
DVでは、データベース側で自動的にJSONとテーブル構造の双方向変換を行います。
開発者はJSON形式のまま直接データを扱えるため、コード量が削減され、迅速なアプリ開発が可能です。
    - ② データ整合性・一貫性の維持
JSONデータを使う場合、「自由なフォーマットのため整合性を維持しにくい」という課題があります。
DVはリレーショナルデータベース（制約、外部キー、トランザクション管理）の強力な整合性をJSONに提供します。
JSONでデータを更新するだけで、データベースレベルの整合性チェックが自動的に行われます。
    - ③ リアルタイムな双方向データ連携
JSONで行った更新は即座にリレーショナルDBに反映されます。逆も同様です。
例えば、Webやモバイルアプリ（JSON中心）と業務システム（RDB中心）の間でのリアルタイムなデータ連携 が簡単に実現できます。
    - ④ パフォーマンス最適化
通常のJSON処理で発生する、アプリケーション層での複雑な変換処理やデータのパース処理が不要になります。
これにより、アプリケーションのレスポンスが速くなり、全体的なパフォーマンスが改善 されます。
    - ⑤ 柔軟で迅速なAPI提供
DVを使ってJSON形式で公開すると、簡単にREST API化できます（AutoRESTと組み合わせ）。
これにより、外部アプリケーションやサービスとの迅速かつ柔軟な連携が可能になります。

# Handsonシナリオ概要
- ゴール：
  - カーレースでのチーム、個人結果の記録、閲覧するアプリの作成
  - アプリはREST、SQLでのアクセスを想定
- シナリオのステップ
  - 事前準備
  - データロード
  - クエリ
  - データ更新
    - マスタ修正：レース名修正
    - マスタ修正：チームメンバー変更（チームメンバーの移籍対応）
  - データ削除

# Handsonの実施

## 前提
- OCI/ADB(Autonomous Database)の基本的な操作ができる
- ADB 23ai環境がセットアップされている
  - Publicからのアクセスが可能
- curlコマンドを実行できる環境がある
## 準備
### ユーザ作成
adminでADBにアクセスのうえ、HOL23AIユーザを作成

```SQL
-- USER SQL
CREATE USER HOL23AI IDENTIFIED BY Welcome12345#;

-- ADD ROLES
GRANT CONNECT TO HOL23AI;
GRANT RESOURCE TO HOL23AI;


-- REST ENABLE
BEGIN
    ORDS_ADMIN.ENABLE_SCHEMA(
        p_enabled => TRUE,
        p_schema => 'HOL23AI',
        p_url_mapping_type => 'BASE_PATH',
        p_url_mapping_pattern => 'hol23ai',
        p_auto_rest_auth=> TRUE
    );
    -- ENABLE DATA SHARING
    C##ADP$SERVICE.DBMS_SHARE.ENABLE_SCHEMA(
            SCHEMA_NAME => 'HOL23AI',
            ENABLED => TRUE
    );
    commit;
END;
/

-- QUOTA
ALTER USER HOL23AI QUOTA UNLIMITED ON DATA;
```

---

＝＝ 以降は、HOL23AIユーザで実施 ＝＝


### Tableの作成
- チームテーブル作成
```SQL
CREATE TABLE IF NOT EXISTS team
    (team_id INTEGER GENERATED BY DEFAULT ON NULL AS IDENTITY,
    name    VARCHAR2(255) NOT NULL UNIQUE,
    points  INTEGER NOT NULL,
    CONSTRAINT team_pk PRIMARY KEY(team_id));
```
- ドライバーテーブル作成
```SQL
CREATE TABLE IF NOT EXISTS driver
    (driver_id INTEGER GENERATED BY DEFAULT ON NULL AS IDENTITY,
    name      VARCHAR2(255) NOT NULL UNIQUE,
    points    INTEGER NOT NULL,
    team_id   INTEGER,
    CONSTRAINT driver_pk PRIMARY KEY(driver_id),
    CONSTRAINT driver_fk FOREIGN KEY(team_id) REFERENCES team(team_id));

```

- レーステーブル作成
```SQL
CREATE TABLE IF NOT EXISTS race
    (race_id   INTEGER GENERATED BY DEFAULT ON NULL AS IDENTITY,
    name      VARCHAR2(255) NOT NULL UNIQUE,
    laps      INTEGER NOT NULL,
    race_date DATE,
    podium    JSON,
    CONSTRAINT   race_pk PRIMARY KEY(race_id));
```


- レース結果記録テーブル作成
```SQL
CREATE TABLE IF NOT EXISTS driver_race_map
    (driver_race_map_id INTEGER GENERATED BY DEFAULT ON NULL AS IDENTITY,
    race_id            INTEGER NOT NULL,
    driver_id          INTEGER NOT NULL,
    position           INTEGER,
    CONSTRAINT     driver_race_map_pk  PRIMARY KEY(driver_race_map_id),
    CONSTRAINT     driver_race_map_fk1 FOREIGN KEY(race_id)   REFERENCES race(race_id),
    CONSTRAINT     driver_race_map_fk2 FOREIGN KEY(driver_id) REFERENCES driver(driver_id));
```

### ERイメージ

上記で作成した４つのテーブルのERイメージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38031/fc738fe1-f013-421c-a1c0-e24719ff10af.png)



### Triggerの作成
ポイント（レース結果で得られるポイント）を自動で付与するためのトリガーの作成
- レース記録を登録すると、結果に応じたポイントをチーム、ドライバーに付与する

```SQL
CREATE OR REPLACE TRIGGER driver_race_map_trigger
BEFORE INSERT ON driver_race_map
FOR EACH ROW
DECLARE
    v_points  INTEGER;
    v_team_id INTEGER;
BEGIN
SELECT team_id INTO v_team_id FROM driver WHERE driver_id = :NEW.driver_id;

IF :NEW.position = 1 THEN
    v_points := 25;
ELSIF :NEW.position = 2 THEN
    v_points := 18;
ELSIF :NEW.position = 3 THEN
    v_points := 15;
ELSIF :NEW.position = 4 THEN
    v_points := 12;
ELSIF :NEW.position = 5 THEN
    v_points := 10;
ELSIF :NEW.position = 6 THEN
    v_points := 8;
ELSIF :NEW.position = 7 THEN
    v_points := 6;
ELSIF :NEW.position = 8 THEN
    v_points := 4;
ELSIF :NEW.position = 9 THEN
    v_points := 2;
ELSIF :NEW.position = 10 THEN
    v_points := 1;
ELSE
    v_points := 0;
END IF;

UPDATE driver SET points = points + v_points
    WHERE driver_id = :NEW.driver_id;
UPDATE team SET points = points + v_points
    WHERE team_id = v_team_id;
END;
/
```

### Duality Viewの作成

- チームテーブル用のDuality View
```SQL
CREATE OR REPLACE JSON RELATIONAL DUALITY VIEW driver_dv AS
SELECT JSON {'_id'    IS d.driver_id,
        'name'     IS d.name,
        'points'   IS d.points,
        UNNEST
            (SELECT JSON {'teamId' IS t.team_id,
                        'team'   IS t.name WITH NOCHECK}
                FROM team t WITH NOINSERT NOUPDATE NODELETE
                WHERE t.team_id = d.team_id),
        'race'     IS
            [ SELECT JSON {'driverRaceMapId' IS drm.driver_race_map_id,
                            UNNEST
                            (SELECT JSON {'raceId' IS r.race_id,
                                            'name'   IS r.name}
                                FROM race r WITH NOINSERT NOUPDATE NODELETE
                                WHERE r.race_id = drm.race_id),
                            'finalPosition'   IS drm.position}
                FROM driver_race_map drm WITH INSERT UPDATE NODELETE
                WHERE drm.driver_id = d.driver_id ]}
FROM driver d WITH INSERT UPDATE DELETE;
```

- ドライバー用のDuality View
```SQL
CREATE OR REPLACE JSON RELATIONAL DUALITY VIEW team_dv AS
SELECT JSON {'_id'   IS t.team_id,
        'name'    IS t.name,
        'points'  IS t.points,
        'driver'  IS
            [ SELECT JSON {'driverId' IS d.driver_id,
                            'name'     IS d.name,
                            'points'   IS d.points WITH NOCHECK}
                FROM driver d WITH INSERT UPDATE
                WHERE d.team_id = t.team_id ]}
FROM team t WITH INSERT UPDATE DELETE;
```

- レース用のDuality View
```SQL
CREATE OR REPLACE JSON RELATIONAL DUALITY VIEW race_dv AS
SELECT JSON {'_id'  IS r.race_id,
        'name'   IS r.name,
        'laps'   IS r.laps WITH NOUPDATE,
        'date'   IS r.race_date,
        'podium' IS r.podium WITH NOCHECK,
        'result' IS
            [ SELECT JSON {'driverRaceMapId' IS drm.driver_race_map_id,
                            'position'        IS drm.position,
                            UNNEST
                            (SELECT JSON {'driverId' IS d.driver_id,
                                            'name'     IS d.name}
                                FROM driver d WITH NOINSERT UPDATE NODELETE
                                WHERE d.driver_id = drm.driver_id)}
                FROM driver_race_map drm WITH INSERT UPDATE DELETE
                WHERE drm.race_id = r.race_id ]}
FROM race r WITH INSERT UPDATE DELETE;
```

### REST APIの設定

```SQL
begin
ORDS.ENABLE_OBJECT(
    P_ENABLED        => TRUE,
    P_SCHEMA         => 'HOL23AI',
    P_OBJECT         =>  'DRIVER_DV',
    P_OBJECT_TYPE    => 'VIEW',
    P_OBJECT_ALIAS   => 'driver_dv',
    P_AUTO_REST_AUTH => FALSE
);
COMMIT;
ORDS.ENABLE_OBJECT(
    P_ENABLED        => TRUE,
    P_SCHEMA         => 'HOL23AI',
    P_OBJECT         =>  'RACE_DV',
    P_OBJECT_TYPE    => 'VIEW',
    P_OBJECT_ALIAS   => 'race_dv',
    P_AUTO_REST_AUTH => FALSE
);
COMMIT;
ORDS.ENABLE_OBJECT(
    P_ENABLED        => TRUE,
    P_SCHEMA         => 'HOL23AI',
    P_OBJECT         =>  'TEAM_DV',
    P_OBJECT_TYPE    => 'VIEW',
    P_OBJECT_ALIAS   => 'team_dv',
    P_AUTO_REST_AUTH => FALSE
);
COMMIT;
end;
/
```

### REST/cURLでのアクセス確認

- RESTエンドポイントの確認
- Getリクエスト

※ この時点ではデータがないため、アウトプットは item=[]となる

```bash
export ADB_BASE_URL=<YOUR_UNIQUE_ADB_URL>

# チームDV
$ curl -X GET $ADB_BASE_URL/ords/hol23ai/team_dv/

# ドライバーDV
$ curl -X GET $ADB_BASE_URL/ords/hol23ai/driver_dv/

# レースDV
$ curl -X GET $ADB_BASE_URL/ords/hol23ai/race_dv/

```

アウトプット例
```
{"items":[],"hasMore":false,"limit":25,"offset":0,"count":0,"links":[{"rel":"self","href":"https://-----.adb.ap-tokyo-1.oraclecloudapps.com/ords/hol23ai/team_dv/"},{"rel":...
```

- 補足
ADBコンソールからcURLコマンドを生成・確認することが可能

Database Actions - 開発/RESTを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38031/a7e71b90-0276-46f6-a8bb-97d03b153316.png)

AUTORESTを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38031/48b106ac-97ab-4c28-a73d-a8d929279654.png)

cURLの取得を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38031/454ddfb4-94b6-4190-870f-b931745ccad0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38031/725b168c-9be5-4574-8e18-7f681fbe73b0.png)


## Populate Duality Views

OCI Cloud Shellなどのlinux環境にて作業用ファイルをダウンロード

```bash
$ mkdir json-autorest
cd json-autorest
wget -O json_autorest.zip https://objectstorage.eu-frankfurt-1.oraclecloud.com/p/Tjh1Lpwt8gDG458HW4aPKL240xohfcD_j4pUNMZhQuVXdrHndzrqEeuNX2F836BS/n/oraclepartnersas/b/WS-files/o/DualityWS/json_autorest.zip
unzip json_autorest.zip
```

### データインサート： 1ドキュメント

```bash
$ curl -i -X POST --data-binary @teamMercedes.json -H "Content-Type: application/json" $ADB_BASE_URL/ords/hol23ai/team_dv/
```

参考: データの中身
```json
{
    "_id": 2,
    "name": "Mercedes",
    "points": 0,
    "driver": [
    {
        "driverId": 105,
        "name": "George Russell",
        "points": 0
    },
    {
        "driverId": 106,
        "name": "Lewis Hamilton",
        "points": 0
    }
    ]
}
```


### データインサート： bulk
```bash
$ curl -i -X POST --data-binary @team.json -H "Content-Type: application/json" $ADB_BASE_URL/ords/hol23ai/team_dv/batchload

$ curl -i -X POST --data-binary @race.json -H "Content-Type: application/json" $ADB_BASE_URL/ords/hol23ai/race_dv/batchload

```



参考: データの中身（チーム+ドライバー）
```json
[
    {
    "_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
        }
    ]
    }
]
```

## クエリ：Duality Viewsへの問い合わせ

例： ドライバーDV
```bash
$ curl -X GET $ADB_BASE_URL/ords/hol23ai/driver_dv/ | jq .
```

```json
{
  "items": [
    {
      "_id": 105,
      "name": "George Russell",
      "points": 0,
      "teamId": 2,
      "team": "Mercedes",
      "race": [],
      "_metadata": {
        "etag": "A8BB1825F6218EC0D300671173540597",
        "asof": "000028CE7D0DED5A"
      },
      "links": [
        {
          "rel": "self",
          "href": "https://sya6vphk3pzlkhq-dw4ai.adb.ap-tokyo-1.oraclecloudapps.com/ords/hol23ai/driver_dv/105"
        }
      ]
    },
    {
      "_id": 106,
      "name": "Lewis Hamilton",
      "points": 0,
      "teamId": 2,
      "team": "Mercedes",
      "race": [],
      "_metadata": {
        "etag": "D3FF3213793E306204BB5E5060368E41",
        "asof": "000028CE7D0DED5A"
      },
      "links": [
        {
          "rel": "self",
          "href": "https://sya6vphk3pzlkhq-dw4ai.adb.ap-tokyo-1.oraclecloudapps.com/ords/hol23ai/driver_dv/106"
        }
      ]
    },

```

例：特定のデータ（主キー検索）
```bash
$ curl -X GET $ADB_BASE_URL/ords/hol23ai/driver_dv/105 | jq .
```

```json
{
  "_id": 105,
  "name": "George Russell",
  "points": 0,
  "teamId": 2,
  "team": "Mercedes",
  "race": [],
  "_metadata": {
    "etag": "A8BB1825F6218EC0D300671173540597",
    "asof": "000028CE7D150DBF"
  },
  "links": [
    {
      "rel": "self",
      "href": "https://sya6vphk3pzlkhq-dw4ai.adb.ap-tokyo-1.oraclecloudapps.com/ords/hol23ai/driver_dv/105"
    },
    {
      "rel": "describedby",
      "href": "https://sya6vphk3pzlkhq-dw4ai.adb.ap-tokyo-1.oraclecloudapps.com/ords/hol23ai/metadata-catalog/driver_dv/item"
    },
    {
      "rel": "collection",
      "href": "https://sya6vphk3pzlkhq-dw4ai.adb.ap-tokyo-1.oraclecloudapps.com/ords/hol23ai/driver_dv/"
    }
  ]
}

```

例：特定のデータ（Query Parameterを用いた検索）

レース名が「"Bahrain Grand Prix"」のものを検索

```bash
{"name":{"$eq":"Bahrain Grand Prix"}}
```

```bash
$ curl -v --location -g "$ADB_BASE_URL/ords/hol23ai/race_dv/?q=%7B%22name%22%3A%7B%22%24eq%22%3A%22Bahrain%20Grand%20Prix%22%7D%7D" | jq .
```

```json
{
  "items": [
    {
      "_id": 201,
      "name": "Bahrain Grand Prix",
      "laps": 57,
      "date": "2022-03-20T00:00:00",
      "podium": {},
      "result": [],
      "_metadata": {
        "etag": "2E8DC09543DD25DC7D588FB9734D962B",
        "asof": "000028CE7D19E145"
      },
      "links": [
        {
          "rel": "self",
          "href": "https://sya6vphk3pzlkhq-dw4ai.adb.ap-tokyo-1.oraclecloudapps.com/ords/hol23ai/race_dv/201"
        }
      ]
    }
  ],
  "hasMore": false,
  "limit": 25,
  "offset": 0,
  "count": 1,
  "links": [
    {
      "rel": "self",
      "href": "https://sya6vphk3pzlkhq-dw4ai.adb.ap-tokyo-1.oraclecloudapps.com/ords/hol23ai/race_dv/?q=%7B%22name%22:%7B%22%24eq%22:%22Bahrain+Grand+Prix%22%7D%7D"
    },
    {
      "rel": "describedby",
      "href": "https://sya6vphk3pzlkhq-dw4ai.adb.ap-tokyo-1.oraclecloudapps.com/ords/hol23ai/metadata-catalog/race_dv/"
    },
    {
      "rel": "first",
      "href": "https://sya6vphk3pzlkhq-dw4ai.adb.ap-tokyo-1.oraclecloudapps.com/ords/hol23ai/race_dv/?q=%7B%22name%22:%7B%22%24eq%22:%22Bahrain+Grand+Prix%22%7D%7D"
    }
  ]
}

```

### クエリ：SQLで各テーブルの内容確認

```sql
select * from team;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38031/ce7fa21b-772f-47b1-a4c0-527172364350.png)



```sql
select * from driver;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38031/da626498-ad65-4605-82f8-cd7175215fb2.png)



```sql
select * from race;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38031/9b9796d1-474f-43a4-832e-4c5f450d8a11.png)


## 更新： Duality ViewsをJSON/PUTで更新する
### Optimistic Lockへの対応
- 更新対象データのIDとetag情報を取得
- 取得したID、etag情報をもとにデータを更新する


例：
- ID、etagの取得

```bash
$ curl -v --location -g "$ADB_BASE_URL/ords/hol23ai/race_dv/?q=%7B%22name%22%3A%7B%22%24eq%22%3A%22Bahrain%20Grand%20Prix%22%7D%7D" | jq .
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38031/829cf2b5-2dc5-4fb5-af67-67f00aa659af.png)

- 取得したetagをJSONに書き込む

```bash
% vim updateRace.json 
```

以下の"UPDATE ETAG HERE"のところに取得したETAG情報を埋め込む

```bash
 1 {
  2   "_metadata": {
  3     "etag": "UPDATE ETAG HERE" ### ここにETAGを埋め込む
  4   },
  5   "_id": 201,
  6   "name": "Bahrain Grand Prix",
  7   "laps": 57,
  8   "date": "2022-03-20T00:00:00",
  9   "podium": {
 10     "winner": {
 11       "name": "Charles Leclerc",
 12       "time": "01:37:33.584"
 13     },

```

- 書き込んだJSONを使ってREST/PUTする

```bash
$ curl -i -X PUT --data-binary @updateRace.json -H "Content-Type: application/json" $ADB_BASE_URL/ords/hol23ai/race_dv/201

```

```sql
select * from DRIVER_RACE_MAP
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38031/e64a742a-3e02-4d2b-8b81-c02de2dbd979.png)



### チームメンバー変更シナリオ
「"Mercedes"と"Ferrari"の間でドライバーがトレードされた」ことを想定した更新シナリオ

- 現在（更新前）のチームメンバーの確認

以下のクエリーパラメータを用いてteam_dvにクエリのうえ、チームメンバー情報を確認する

```bash
{"name":{"$in":["Mercedes","Ferrari"]}}
```

```bash
$ curl -v --location -g "$ADB_BASE_URL/ords/hol23ai/team_dv/?q=%7B%22name%22%3A%7B%22%24in%22%3A%5B%22Mercedes%22%2C%22Ferrari%22%5D%7D%7D" | jq .
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38031/dbab4cf8-7778-4702-a70a-b01a1279de4a.png)

```sql
select * from team;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38031/10560952-69f9-40bb-b944-1126070b1389.png)


- 変更後のチームデータを更新するJSONを作成（updateMercedes.json、updateFerrari.jsonをアップデート）

```bash
$ cat updateMercedes.json

{
    "_id": 2,
    "name": "Mercedes",
    "points": 40,
    "driver": [
    {
        "driverId": 106,
        "name": "Lewis Hamilton",
        "points": 15
    },
    {
        "driverId": 103,
        "name": "Charles Leclerc",
        "points": 25
    }
    ]
}
```

```bash
$ cat updateFerrari.json
{
"_id": 302,
"name": "Ferrari",
"points": 30,
"driver": [
    {
    "driverId": 105,
    "name": "George Russell",
    "points": 12
    },
    {
    "driverId": 104,
    "name": "Carlos Sainz Jr",
    "points": 18
    }
]
}
```

- 上記更新したJSONを用いたREST/PUTの実行

```bash
# For Mercedes team
$ curl -i -X PUT --data-binary @updateMercedes.json -H "Content-Type: application/json" $ADB_BASE_URL/ords/hol23ai/team_dv/2

# For Ferrari team
$ curl -i -X PUT --data-binary @updateFerrari.json -H "Content-Type: application/json" $ADB_BASE_URL/ords/hol23ai/team_dv/302
```

- 更新後のチームメンバーの確認

```bash
$ curl -v --location -g "$ADB_BASE_URL/ords/hol23ai/team_dv/?q=%7B%22name%22%3A%7B%22%24in%22%3A%5B%22Mercedes%22%2C%22Ferrari%22%5D%7D%7D" | jq .
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38031/fdeabdc8-9f1f-430f-88f4-e08e75df0555.png)

- ドライバーDVの確認

確認に用いるクエリーパラメータ
```bash
{"$or":[{"name":{"$like":"George%"}},{"name":{"$like":"Charles%"}}]}
```

実行
```bash
$ curl -v --location -g  "$ADB_BASE_URL/ords/hol23ai/driver_dv/?q=%7B%22%24or%22:%5B%7B%22name%22:%7B%22%24like%22:%22George%25%22%7D%7D%2C%7B%22name%22:%7B%22%24like%22:%22Charles%25%22%7D%7D%5D%7D" | jq .
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38031/cb2fcfd5-6a39-4475-adc1-fd4bb1f4d306.png)


```sql
select * from DRIVER;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38031/b0a1e77d-868d-4a17-967e-42f9b76c1bd3.png)


- レースDVの確認

```bash
% curl -X GET $ADB_BASE_URL/ords/hol23ai/race_dv/ | jq .
```

```json
{
  "items": [
    {
      "_id": 201,
      "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"
        }
      ],
      "_metadata": {
        "etag": "20F7D9F0C69AC5F959DCA819F9116848",
        "asof": "000028CE8D4A0A14"
      },
      "links": [
        {
          "rel": "self",
          "href": "https://sya6vphk3pzlkhq-dw4ai.adb.ap-tokyo-1.oraclecloudapps.com/ords/hol23ai/race_dv/201"
        }
      ]
    },
    {
      "_id": 202,
      "name": "Saudi Arabian Grand Prix",
      "laps": 50,
      "date": "2022-03-27T00:00:00",
      "podium": {},
      "result": [],
      "_metadata": {
        "etag": "7E056A845212BFDE19E0C0D0CD549EA0",
        "asof": "000028CE8D4A0A14"
      },
      "links": [
        {
          "rel": "self",
          "href": "https://sya6vphk3pzlkhq-dw4ai.adb.ap-tokyo-1.oraclecloudapps.com/ords/hol23ai/race_dv/202"
        }
      ]
    },
    {
      "_id": 203,
      "name": "Australian Grand Prix",
      "laps": 58,
      "date": "2022-04-09T00:00:00",
      "podium": {},
      "result": [],
      "_metadata": {
        "etag": "EA6E1194C012970CA07116EE1EF167E8",
        "asof": "000028CE8D4A0A14"
      },
      "links": [
        {
          "rel": "self",
          "href": "https://sya6vphk3pzlkhq-dw4ai.adb.ap-tokyo-1.oraclecloudapps.com/ords/hol23ai/race_dv/203"
        }
      ]
    }
  ],
  "hasMore": false,
  "limit": 25,
  "offset": 0,
  "count": 3,
  "links": [
    {
      "rel": "self",
      "href": "https://sya6vphk3pzlkhq-dw4ai.adb.ap-tokyo-1.oraclecloudapps.com/ords/hol23ai/race_dv/"
    },
    {
      "rel": "describedby",
      "href": "https://sya6vphk3pzlkhq-dw4ai.adb.ap-tokyo-1.oraclecloudapps.com/ords/hol23ai/metadata-catalog/race_dv/"
    },
    {
      "rel": "first",
      "href": "https://sya6vphk3pzlkhq-dw4ai.adb.ap-tokyo-1.oraclecloudapps.com/ords/hol23ai/race_dv/"
    }
  ]
}
```

### レース名称の修正をマスタ表から実施するシナリオ

- RADE_ID 203:Australian Grand Prixのレース名 → Paciffic Grand Prix
- SQLで上記更新
- RACE_DVでも反映されていることを確認

```sql
update race set name = 'Paciffic Grand Prix' where race_id = 203;
```

```bash
% curl -X GET $ADB_BASE_URL/ords/hol23ai/race_dv/ | jq .
```

```json
{
  "items": [
    {
      "_id": 203,
      "name": "Paciffic Grand Prix",
      "laps": 58,
      "date": "2022-04-09T00:00:00",
      "podium": {},
      "result": [],
      "_metadata": {
        "etag": "137FE8AF997CC26D99FCDAA6B3D00F0D",
        "asof": "000028CE932FCBA4"
      },
      "links": [
        {
          "rel": "self",
          "href": "https://sya6vphk3pzlkhq-dw4ai.adb.ap-tokyo-1.oraclecloudapps.com/ords/hol23ai/race_dv/203"
        }
      ]
    }
  ],

```



### Updateが許可されていないカラムへのUpdate試行 → Errorとなる

```bash
$ curl -i -X PUT --data-binary @updateLeclerc.json -H "Content-Type: application/json" $ADB_BASE_URL/ords/hol23ai/driver_dv/103
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38031/1c116144-010f-4755-8cf4-e9fe440a294e.png)


## 削除： Documentの削除

- IDを指定した削除
- クエリパラメータを用いた削除

例：IDを指定した削除

```bash
$ curl --request DELETE --url $ADB_BASE_URL/ords/hol23ai/race_dv/201
```

例：クエリパラメータを用いた削除

用いるクエリパラメータ
```bash
{"raceId":{"$eq":202}}
```

```bash
$ curl -v --location -g -X DELETE "$ADB_BASE_URL/ords/hol23ai/race_dv/?q=%7B%22_id%22%3A%7B%22%24eq%22%3A202%7D%7D"

```

# 参考

- [JSON-Relational Duality Developer's Guide](https://docs.oracle.com/en/database/oracle/oracle-database/23/jsnvu/index.html)
- [Oralce-Samples - json-relational-duality/README.md](https://github.com/oracle-samples/oracle-db-examples/blob/main/json-relational-duality/README.md)
- [Oracle Database 23ai JSON Relational Duality Views REST APIs](https://www.thatjeffsmith.com/archive/2023/04/oracle-database-23c-json-relational-duality-views-rest-apis/)