5.1 二面性ビューへのドキュメント/データの挿入

JSONドキュメントを二面性ビューに直接挿入することも、二面性ビューの基礎となる表にデータを挿入することもできます。例は、これらの可能性を示しています。

ノート:

特に明示的に示されていないかぎり、次のようになります。

  • ここに示す例は、決して相互に依存するものではありません。特に、それらの間には暗黙的な順序付けはありません。

  • ここでの二面性ビューを使用する例では、「二面性ビューの作成」で定義したビューを使用します。これらのビューは、UNNESTを使用して定義されています(例3-1例3-3および例3-5)。

  • ここでの表を使用する例では、「カーレースの例、表」で定義した表を使用します。

1つ以上の二面性ビューの基礎となるルート表にデータ(行)を挿入すると、各ビューでサポートされる新しいドキュメントが作成されます。その表に指定されたビューのフィールドのみがドキュメントに存在し、他のすべてのフィールドは存在しません。

たとえば、表raceに行を挿入すると、ビューrace_dv (ルート表として表raceを持つ)にドキュメントが挿入され、そのドキュメントにはレース固有のフィールドが含まれています。フィールドresultは、raceではなく、表driverおよびdriver_race_mapから導出されるため、欠落しています。

二面性ビューにドキュメントを挿入すると、そのフィールド値は、対応する表の列に必要なデータ型に自動的に変換されます。たとえば、値がサポートされているISO 8601の日時書式であるJSONフィールドは、対応する列の型がDATEの場合、SQLのDATE型の値に自動的に変換されます。一部のフィールドの型は、必要な列型に変換できない場合、エラーが発生します。

基礎となる表のJSON型の列に対応するフィールドの値では、このような型変換が行われません。テキストJSONドキュメントを挿入する場合は、キーワードEXTENDEDを指定したJSON型コンストラクタを拡張オブジェクトとともに使用して、Oracle固有の型のJSON言語スカラー値(dateなど)を指定できます。たとえば、{"$oracleDate" : "2022-03-27"}などのテキスト・フィールド値を使用して、JSON型の日付値を生成できます。(もちろん、同じ方法を使用して、テキスト・データを、基礎となる表の列に直接挿入するJSON型に変換できます。)

ヒント:

挿入するドキュメントが二面性ビューでサポートされている既存のドキュメントと似ているか、互換性があることを確認するには、ドキュメントの作成時にそれらのドキュメントをガイドとして記述するJSONスキーマを使用します。スキーマは、静的ディクショナリ・ビュー*_JSON_DUALITY_VIEWSの列JSON_SCHEMAから、またはPL/SQLファンクションDBMS_JSON_SCHEMA.describeを使用して取得できます。「二面性ビューに関する情報の取得」を参照してください。

あまり重要でないフィールドや、適切な値が不明なフィールドは省略できます。ただし、実行時エラーを回避するには、JSONスキーマの配列"required"に含まれるすべてのフィールドを含めることをお薦めします。

関連項目:

例5-1 ドキュメント識別子フィールドを指定した二面性ビューへのJSONドキュメントの挿入 — SQLの使用

この例では、ビューteam_dvに3つのドキュメントを挿入し、ビューrace_dvに3つのドキュメントを挿入します。ここでは、_idという名前のドキュメント識別子フィールドが明示的に指定されています。フィールド_idは、二面性ビューのルート表の識別列に対応付けられています。

ここでのレース・ドキュメントのフィールドdateの値は、ISO 8601の日時文字列です。フィールドdateに対応する表raceの列のデータ型がDATEであるため、これらは自動的にSQL DATE値に変換され、基礎となるrace表に挿入されます。

この例では、フィールド/列points (値0)およびpodium (値{})には、基本的なプレースホルダ値のみが指定されています。これらは、ビューとその表に最初に移入するのに使用されます。様々な種類のレースを定義しますが、実際のレース結果は記録しません。

個々のドライバのpointsフィールド/列の値はチーム・ドキュメント/表とドライバ・ドキュメント/表の間で共有されるため、1つの場所でこれらを更新すると、別の場所でも自動的に更新されます。これらの異なるビューでは、フィールド/列は同じ名前ですが、関連はありません。重要なのは、フィールド/列名間ではなく、二面性ビュー間の関係です。

挿入(および削除)と同様に、二面性ビューまたはその基礎となる表に対して更新を直接実行できます(例5-3を参照)。

カーレースの例は、カーレースの結果として動的に更新(置換)されるpointsおよびpodiumフィールドの値を示しています。この更新は、想定されるアプリケーション・ロジックの一部です。つまり、ここではアプリケーションによってそれが実行されるものとします。

しかしながら、チームの二面性ビューの一部として、チームのポイントが必ずそのチームのドライバのポイントの合計になるように宣言的に定義する例について、例7-2を参照してください。これにより、アプリケーションでドライバのポイントの他にチームのポイントを更新する必要がなくなります。

また、アプリケーション・ロジックの一部として、特定のレースにおけるドライバのpositionが、そのドライバの累積されたpointsに関与することが想定されます(ドライバの位置が適切であればあるほど、ポイントが累積されます)。ここではそれについてもアプリケーション・コードで対処するものとします。

-- Insert team documents into TEAM_DV, providing field _id.
INSERT INTO team_dv VALUES ('{"_id"   : 301,
                              "name"   : "Red Bull",
                              "points" : 0,
                              "driver" : [ {"driverId" : 101,
                                            "name"     : "Max Verstappen",
                                            "points"   : 0},
                                           {"driverId" : 102,
                                            "name"     : "Sergio Perez",
                                            "points"   : 0} ]}');

INSERT INTO team_dv VALUES ('{"_id"   : 302,
                              "name"   : "Ferrari",
                              "points" : 0,
                              "driver" : [ {"driverId" : 103,
                                            "name"     : "Charles Leclerc",
                                            "points"   : 0},
                                           {"driverId" : 104,
                                            "name"     : "Carlos Sainz Jr",
                                            "points"   : 0} ]}');

INSERT INTO team_dv VALUES ('{"_id"   : 303,
                              "name"   : "Mercedes",
                              "points" : 0,
                              "driver" : [ {"driverId" : 105,
                                            "name"     : "George Russell",
                                            "points"   : 0},
                                           {"driverId" : 106,
                                            "name"     : "Lewis Hamilton",
                                            "points"   : 0} ]}');

-- Insert race documents into RACE_DV, providing field _id.
INSERT INTO race_dv VALUES ('{"_id"   : 201,
                              "name"   : "Bahrain Grand Prix",
                              "laps"   : 57,
                              "date"   : "2022-03-20T00:00:00",
                              "podium" : {}}');

INSERT INTO race_dv VALUES ('{"_id"   : 202,
                              "name"   : "Saudi Arabian Grand Prix",
                              "laps"   : 50,
                              "date"   : "2022-03-27T00:00:00",
                              "podium" : {}}');

INSERT INTO race_dv VALUES ('{"_id"   : 203,
                              "name"   : "Australian Grand Prix",
                              "laps"   : 58,
                              "date"   : "2022-04-09T00:00:00",
                              "podium" : {}}');

例5-2 ドキュメント識別子フィールドを指定した二面性ビューへのJSONドキュメントの挿入 — RESTの使用

この例では、Oracle REST Data Services (ORDS)を使用して例5-1と同じことを実行します。簡潔にするために、1つのドキュメントのみを二面性ビューteam_dvに挿入し、1つのドキュメントをレース・ビューrace_dvに挿入します。二面性ビューの例を所有するデータベース・ユーザー(スキーマ)は、ここではユーザーJANUSとして表示されます。

ビューteam_dvにドキュメントを挿入します:

curl --request POST \
  --url http://localhost:8080/ords/janus/team_dv/ \
  --header 'Content-Type: application/json' \
  --data '{"_id"   : 302,
           "name"   : "Ferrari",
           "points" : 0,
           "driver" : [ {"driverId" : 103,
                         "name"     : "Charles Leclerc",
                         "points"   : 0},
                        {"driverId" : 104,
                         "name"     : "Carlos Sainz Jr",
                         "points"   : 0} ]}'

レスポンス:

201 Created

{"_id"      : 302,
 "_metadata" : {"etag" : "DD9401D853765859714A6B8176BFC564",
                "asof" : "0000000000000000"},
 "name"      : "Ferrari",
 "points"    : 0,
 "driver"    : [ {"driverId" : 103,
                  "name"     : "Charles Leclerc",
                  "points"   : 0},
                 {"driverId" : 104,
                  "name"     : "Carlos Sainz Jr",
                  "points"   : 0}],
 "links"     : [ {"rel"  : "self",
                  "href" : "http://localhost:8080/ords/janus/team_dv/302"},
                 {"rel"  : "describedby",
                  "href" :
                   "http://localhost:8080/ords/janus/metadata-catalog/team_dv/item"},
                 {"rel"  : "collection",
                  "href" : "http://localhost:8080/ords/janus/team_dv/"} ]}

ビューrace_dvにドキュメントを挿入します:

curl --request POST \
  --url http://localhost:8080/ords/janus/race_dv/ \
  --header 'Content-Type: application/json' \
  --data '{"_id"   : 201,
           "name"   : "Bahrain Grand Prix",
           "laps"   : 57,
           "date"   : "2022-03-20T00:00:00",
           "podium" : {}}'

レスポンス:

201 Created
{"_id"      : 201,
 "_metadata" : {"etag" : "2E8DC09543DD25DC7D588FB9734D962B",
                "asof" : "0000000000000000"},
 "name"      : "Bahrain Grand Prix",
 "laps"      : 57,
 "date"      : "2022-03-20T00:00:00",
 "podium"    : {},
 "result"    : [],
 "links"     : [ {"rel"  : "self",
                  "href" : "http://localhost:8080/ords/janus/race_dv/201"},
                 {"rel"  : "describedby",
                  "href" :
                   "http://localhost:8080/ords/janus/metadata-catalog/race_dv/item"},
                 {"rel"  : "collection",
                  "href" : "http://localhost:8080/ords/janus/race_dv/"} ]}

ノート:

最適なパフォーマンスを得るには、Oracle REST Data Services (ORDS)を構成して、1秒のタイムアウトを指定してメタデータ・キャッシュを有効にしにます:

cache.metadata.enabled = true
cache.metadata.timeout = 1

『Oracle REST Data Servicesインストレーションおよび構成ガイド』の「REST対応SQLサービス設定の構成」を参照してください。

関連項目:

『Oracle REST Data Services開発者ガイド』JSONリレーショナル二面性ビューのサポート

例5-3 表へのJSONデータの挿入

この例では、JSONドキュメント二面性ビューに挿入する別の方法を示します。teamおよびraceにJSON データを挿入します。

挿入されたデータは、関連するドキュメントの一部(ビュー・タイプに固有の部分)にのみ対応しています。各表には、別の表が対象としていないデータのみの列があります(表は正規化されます)。

表データは正規化されるため、ビューでサポートされているドキュメントを含め、データが使用されているすべての場所に表行の挿入が反映されます。

ここで、例5-1のように、チームのポイントとレースの表彰者には、基本の(初期)値が与えられます。

INSERT INTO team VALUES (301, 'Red Bull', 0);
INSERT INTO team VALUES (302, 'Ferrari',  0);
   
INSERT INTO race
  VALUES (201, 'Bahrain Grand Prix',       57, DATE '2022-03-20', '{}');
INSERT INTO race
  VALUES (202, 'Saudi Arabian Grand Prix', 50, DATE '2022-03-27', '{}');
INSERT INTO race
  VALUES (203, 'Australian Grand Prix',    58, DATE '2022-04-09', '{}');

例5-4 ドキュメント識別子フィールドの指定のない二面性ビューへのJSONドキュメントの挿入 — SQLの使用

この例では、ドキュメント識別子フィールド(_id)を指定せずに、二面性ビューdriver_dvにドライバ・ドキュメントを挿入します。このフィールドの値は自動的に生成されます(基になる識別列(この場合は主キー列)がINTEGER GENERATED BY DEFAULT ON NULL AS IDENTITYを使用して定義されているため)。次に、生成されたフィールド値を出力します。


-- Insert a driver document into DRIVER_DV, without providing a
--  document-identifier field (_id).  The field is provided
--  automatically, with a generated, unique numeric value.
-- SQL/JSON function json_value is used to return the value into bind
--  variable DRIVERID.
VAR driverid NUMBER;
INSERT INTO driver_dv dv VALUES ('{"name"   : "Liam Lawson",
                                   "points" : 0,
                                   "teamId" : 301,
                                   "team" : "Red Bull",
                                   "race"   : []}')
  RETURNING json_value(DATA, '$._id') INTO :driverid;

SELECT json_serialize(data PRETTY) FROM driver_dv d
  WHERE d.DATA.name = 'Liam Lawson';

{"_id"      : 7,
 "_metadata" : {"etag" : "F9D9815DFF27879F61386CFD1622B065",
                "asof" : "00000000000C20CE"},
 "name"      : "Liam Lawson",
 "points"    : 0,
 "teamId"    : 301,
 "team"      : "Red Bull",
 "race"      : []}

例5-5 ドキュメント識別子フィールドの指定のない二面性ビューへのJSONドキュメントの挿入 — RESTの使用

この例では、Oracle REST Data Services (ORDS)を使用して例5-4と同じことを実行します。二面性ビューの例を所有するデータベース・ユーザー(スキーマ)は、ここではユーザーJANUSとして表示されます。

curl --request POST \
  --url http://localhost:8080/ords/janus/driver_dv/ \
  --header 'Content-Type: application/json' \
  --data '{"name"   : "Liam Lawson",
           "points" : 0,
           "teamId" : 301,
           "team"   : "Red Bull",
           "race"   : []}'

レスポンス:

201 Created
{"_id"      : 7,
 "_metadata" : {"etag" : "F9EDDA58103C3A601CA3E0F49E1949C6",
                "asof" : "00000000000C20CE"},
 "name"      : "Liam Lawson",
 "points"    : 0,
 "teamId"    : 301,
 "team"      : "Red Bull",
 "race"      : [],
 "links"     :
  [ {"rel"  : "self",
     "href" : "http://localhost:8080/ords/janus/driver_dv/23"},
    {"rel"  : "describedby",
     "href" : "http://localhost:8080/ords/janus/metadata-catalog/driver_dv/item"},
    {"rel"  : "collection",
     "href" : "http://localhost:8080/ords/janus/driver_dv/"} ]}

ノート:

最適なパフォーマンスを得るには、Oracle REST Data Services (ORDS)を構成して、1秒のタイムアウトを指定してメタデータ・キャッシュを有効にしにます:

cache.metadata.enabled = true
cache.metadata.timeout = 1

『Oracle REST Data Servicesインストレーションおよび構成ガイド』の「REST対応SQLサービス設定の構成」を参照してください。

関連項目:

『Oracle REST Data Services開発者ガイド』JSONリレーショナル二面性ビューのサポート