2 Oracle Database API for MongoDBを使用したアプリケーションの開発
アプリケーションを開発または移行する際の考慮事項 — (1)ハウツー情報と(2)相違点および実行可能な調整の説明との組合せ。
- 索引付けとパフォーマンス・チューニング
Oracle Databaseでは、索引、マテリアライズド・ビュー、インメモリー列記憶域、Exadataストレージ・セルのプッシュダウンなど、JSONデータに対する問合せを加速する複数のテクノロジが用意されています。パフォーマンス・チューニングに対するアプローチは、アプリケーションのニーズによって異なります。 - ユーザー、認証および認可
Oracle Databaseのセキュリティは、MongoDBのセキュリティとは大きく異なります。Oracle Database API for MongoDBのセキュリティ・モデルについて説明します(様々な操作を実行するためのユーザーの作成、ユーザーの認証およびユーザーの認可)。 - MongoDBからOracle Databaseへのアプリケーション・データの移行
MongoDBからJSONデータをエクスポートし、さらにそれをOracle Databaseにインポートするいくつかの方法について説明します。移行に関する考慮事項について説明します。 - MongoDB集計パイプラインのサポート
Oracle Database API for MongoDBでは、MongoDB集計パイプライン、つまりMongoDBコマンドaggregate
がサポートされています。パイプライン・コードを使用して、一連の操作として問合せを実行できます。このプロシージャ型アプローチの宣言型の代替としてSQLを使用することもできます。 - MongoDBドキュメントとOracle Database
ここでは、MongoDBで使用されるJSONドキュメントとOracle Databaseで格納され使用されるJSONドキュメントとの関係を示します。 - MongoDBとOracle Databaseとのその他の相違点
MongoDBとOracle Databaseの様々な相違点について説明します。これらの相違点には、通常、他のトピックでは触れていません。アプリケーションをOracle Databaseに移行する場合や、MongoDBコマンドを使用するOracle Database向けの新しいアプリケーションを開発する場合に、これらの相違点を考慮してください。 - 他のユーザー(データベース・スキーマ)が所有するコレクションへのアクセス
そのスキーマにログインすると、別のユーザー(データベース・スキーマ)が所有するMongoDB APIコレクションに直接アクセスできます。そのコレクションが自分のスキーマ内のコレクションにマップされている場合は、そのスキーマにログインせずに、別のユーザーが所有するコレクションに間接的にアクセスできます。
2.1 索引付けおよびパフォーマンス・チューニング
Oracle Databaseでは、索引、マテリアライズド・ビュー、インメモリー列記憶域、Exadataストレージ・セルのプッシュダウンなど、JSONデータに対する問合せを加速する複数のテクノロジが用意されています。パフォーマンス・チューニングに対するアプローチは、アプリケーションのニーズによって異なります。
Oracle Databaseのcompatible
パラメータが23
以上の場合は、MongoDBの索引操作createIndex
およびdropIndex
を使用して、関連するOracle索引を自動的に作成および削除できます。compatible
パラメータが23
より小さい場合、このようなMongoDBの索引操作はサポートされていないため、これらは無視されます。
データベース・リリースに関係なく、(1) Oracle Database Actionsの使用のJSONページ(JSONコレクションの索引の作成を参照)、(2) Simple Oracle Document Access (SODA)または(3) SQLを使用して、必要なすべてのOracle Database索引を直接作成できます。Oracle Database JSON開発者ガイドのJSONデータの索引を参照してください。JSONデータを索引付けする場合は、通常、JSONページを使用する方法が最も簡単になります。
ノート:
MongoDBでは、同じデータベース内の複数の異なるコレクションに同じ名前の索引を使用できます。これはOracle Databaseでは許可されません。索引の名前は、特定のデータベース・スキーマ(データベース)のすべてのコレクションで一意である必要があります。
たとえば、次のような購買オーダー・ドキュメントのorders
というコレクションに索引を付けるとします:
{ "PONumber" : 1600,
"User" : "ABULL",
"LineItems" : [{ "Part" : { "Description" : "One Magic Christmas",
"UnitPrice" : 19.95,
"UPCCode" : 13131092899 },
"Quantity" : 9.0 },
{ "Part" : { "Description" : "Lethal Weapon",
"UnitPrice" : 19.95,
"UPCCode" : 85391628927
},
"Quantity" : 5.0 } ]}
2つの重要なユース・ケースは、(1)シングルトン・スカラー・フィールド、つまりドキュメントに1回のみ出現するフィールドを索引付けすることと、(2)配列の要素内のオブジェクトにあるスカラー・フィールドを索引付けすることです。フィールドPONumber
の値を索引付けすることが最初のケースの例です。フィールドUPCCode
の値を索引付けすることが2番目のケースの例です。
例2-1、例2-2および例2-3に、最初のケースを示します。例2-5に、2番目のケースを示します。
また、SDO_GEOMETRY
データを返すファンクションベースのSQL索引を使用して、GeoJSON (空間)データを索引付けすることもできます。さらに、すべてのJSONデータに対して、JSON検索索引を作成してから、SQL/JSON条件json_textcontains
を使用して全文問合せを実行できます。
例2-1 Database ActionsのJSONページを使用したシングルトン・スカラー・フィールドの索引付け
JSONページを使用してフィールドPONumber
の索引を作成するには、次の手順を実行します。
-
コレクション名(
orders
)を右クリックし、ポップアップ・メニューから「Indexes」を選択します。
図json_page_create_index_001.pngの説明 -
「New Index」ページで、次の手順を実行します。
-
「Properties」検索ボックスに
*
を入力します。これにより、「Properties」リストに、コレクション内のすべてのスカラー・フィールドへのパスが移入されます。これらのパスは、JSONデータ・ガイドを使用してコレクション・データをサンプリングすることで提供されます。Oracle Database SQL言語リファレンスのJSON_DATAGUIDEを参照してください。
オプション「Advanced」をオンにした場合は、スライダを右に押すと、リストされているスカラー・フィールドのタイプも表示されます。表示されるタイプは、コレクションをサンプリングすることで選択されるタイプです。ただし、索引付けする目的でフィールドのタイプを変更できます。
-
索引付けするフィールドのパスを選択します。このケースでは、1つのスカラー・フィールド
PONumber
のみを索引付けするため、それを選択します。ノート: このダイアログ・ボックスでは、複数のパスを選択できます。複数のパスを選択すると、それらのパスのデータに対してコンポジット索引が作成されます。脚注1ただし、2つの異なるフィールドを個別に索引付けする場合は、1つのコンポジット索引(両方のフィールドをまとめて索引付けする)ではなく2つの索引を作成します。
索引データ型は選択したパス上にあるデータの型によって自動的に決定されますが、「Automatic」を有効にしてデータ型を変更することで、これを制御できます。たとえば、特定のフィールドのコレクション・データにJSON番号があると、
number
型がリストされますが、これをVARCHAR2
に編集して、文字列値として強制的に索引付けできます。
フィールド
PONumber
の値は一意です。コレクションで同じ数値がフィールドに複数回使用されないため、「Unique」の索引を選択します。「Index Nulls」も選択します。これは、
ORDER BY
を使用して結果をソートする問合せに必要です。これにより、すべてのドキュメントが索引内にエントリを持つようになります。フィールド
PONumber
の値はJSON数値です。つまり、数値の比較に索引を使用できます。
図json_page_create_index_002.pngの説明 -
例2-2 SODAを使用したシングルトン・スカラー・フィールドの索引付け
索引付けをサポートするSODA実装(プログラミング言語またはフレームワーク)ごとに、索引を作成する方法が用意されています。それらはすべて、SODA索引仕様を使用して、作成する索引を定義します。たとえば、SODA for RESTでは、HTTP POSTリクエストを使用してURI引数action=index
を渡し、POST本体に索引仕様を提供します。
これは、フィールドPONumber
のpoNumIdx
という一意の索引に対するSODA索引仕様です。
{ "name" : "poNumIdx",
"unique" : true,
"fields" : [ { "path" : "PONumber",
"dataType" : "NUMBER",
"order" : "ASC" } ] }
例2-3 SQLを使用したシングルトン・スカラー・フィールドの索引付け
Database Actionsを使用すると、このSQLコードで表orders
の列data
にフィールドPONumber
の索引を作成できます。これは、SQL/JSONファンクションjson_value
を使用して、フィールドPONumber
の値を抽出します。
ドキュメントにPONumber
フィールドがない場合や複数ある場合、コードはERROR ON ERROR
処理を使用してエラーを生成します。
索引付けするフィールドを識別するパス式で項目メソッドnumberOnly()
を使用して、フィールド値が数値であることを確認します。
number()
では、数値以外のフィールドを数値に変換することもできるため、メソッドnumber()
のかわりにメソッドnumberOnly()
を使用します。たとえば、number()
は、PONumber
の文字列値"42"
を数値の42
に変換します。
同様に厳密に型チェックをする、このような"only"付きの項目メソッドとして、stringOnly()
、dateTimeOnly()
およびbinaryOnly()
などが、文字列、日付およびバイナリ値用にそれぞれ用意されています。
CREATE UNIQUE INDEX "poNumIdx" ON orders
(json_value(data, '$.PONumber.numberOnly()' ERROR ON ERROR))
関連項目:
Oracle Database JSON開発者ガイドのSQL/JSONパス式の項目メソッド
例2-4 配列の要素内のフィールドに対する複数値索引の作成
Oracle Database 21c以降では、配列内のオブジェクト(要素または要素内の下位レベルのオブジェクト)にフィールドが含まれるためにドキュメントに複数回発生する可能性があるフィールドの値に対して複数値索引を作成できます。
この例では、フィールドUPCCode
の値のコレクションorders
に複数値索引を作成します。この例では、項目メソッドnumberOnly()
を使用するため、数値のUPCCode
フィールドにのみ適用されます。
CREATE MULTIVALUE INDEX mvi_UPCCode ON orders o
(o.data.LineItems.Part.UPCCode.numberOnly());
関連項目:
Oracle Database JSON開発者ガイドのJSON_EXISTSの複数値ファンクションベースの索引の作成
例2-5 配列の要素内のフィールドに対するマテリアライズド・ビューおよび索引の作成
Oracle Database 21cより前は、配列内のオブジェクト(要素または要素内の下位レベルのオブジェクト)にフィールドが含まれているためにドキュメントに複数回出現する可能性がある、UPCCode
などのフィールドに対して複数値索引を作成できません。
かわりに、この例のように、索引付けするデータを抽出するマテリアライズド・ビューを作成してから、そのビュー・データに対してファンクション索引を作成できます。
この例では、列upccode
を含むマテリアライズド・ビューmv_UPCCode
が作成されています。これは、表orders
の列data
の配列LineItems
にあるPart
オブジェクト内のフィールドUPCCode
の投影です。次に、マテリアライズド・ビュー(mv_UPCCode
)の列upccode
に対して索引mv_UPCCode_idx
が作成されます。
CREATE MATERIALIZED VIEW mv_UPCCode
BUILD IMMEDIATE
REFRESH FAST ON STATEMENT WITH PRIMARY KEY
AS SELECT o.id, jt.upccode
FROM orders o,
json_table(data, '$.LineItems[*]'
ERROR ON ERROR NULL ON EMPTY
COLUMNS (upccode NUMBER PATH '$.Part.UPCCode')) jt;
CREATE INDEX mv_UPCCode_idx ON mv_UPCCode(upccode);
問合せオプティマイザは、リクエストされたデータにSQL文が最も効率的にアクセスする方法を見つける役割を担います。特に、問合せ対象のデータに適用される索引を使用するかどうかと、複数の索引が関連している場合にどの索引を使用するかを決定します。ほとんどの場合は、オプティマイザの判断に委ねることが最適なガイドラインとなります。
ただし、問合せによっては特定の索引を選択するように指定することもできます。これは、索引名を指定するMongoDB hintを使用して行うことができます。(オラクル社はMongoDB索引仕様の使用をサポートしていません。単に索引名を指定します。)
たとえば、この問合せでは、例2-1で作成したコレクションorders
の索引poNumIdx
を使用します。
db.orders.find({"PONumber":1600}).hint("poNumIdx")
あるいは、MongoDBヒント構文のOracle拡張機能である例による問合せ(QBE)演算子$native
でOracle SQLヒントを渡して、使用する索引を指定することもできます。
$native
の引数には、SQLヒント文字列(つまり、SQLコメント構文/*+...*/
で囲んでいない実際のヒント・テキスト)と同じ構文があります。$native
を使用して任意のSQLヒントを渡すことができます。特に、ヒントMONITOR
を使用して、現在のSQL文のモニタリングを有効にできます。次のコードは、それをfind()
問合せに対して実行します。
db.orders.find().hint({"$native":"MONITOR"})
関連トピック
関連項目:
-
Oracle Database Actionsの使用のJSONページ
-
Oracle Database Simple Oracle Document Access (SODA)の概要のSODA索引付けの概要
-
Oracle Database JSON開発者ガイドのJSON_EXISTSの複数値ファンクションベースの索引の作成
-
JSONデータを使用する場合のパフォーマンス向上の詳細は、Oracle Database JSON開発者ガイドのJSONのパフォーマンス・チューニング
-
JSON検索索引の詳細は、Oracle Database JSON開発者ガイドのアドホック問合せおよびフルテキスト検索のためのJSON検索索引
-
Oracle Database JSON開発者ガイドのスカラーGeoJSONデータの空間索引の作成
-
Oracle Database SQLチューニング・ガイドのヒントによるオプティマイザへの影響
-
データベース操作のモニターの詳細は、Oracle Database SQLチューニング・ガイドのデータベース操作のモニタリング
-
SQLヒント
MONITOR
およびNO_MONITOR
の構文と動作の詳細は、Oracle Database SQLチューニング・ガイドのMONITORヒントとNO_MONITORヒント
2.2 ユーザー、認証および認可
Oracle Databaseのセキュリティは、MongoDBのセキュリティとは大きく異なります。Oracle Database API for MongoDBのセキュリティ・モデルについて説明します(様々な操作を実行するためのユーザーの作成、ユーザーの認証およびユーザーの認可)。
MongoDBの場合、デフォルトではユーザー認証および認可チェックが有効になっていません。Oracle Databaseでは常に認証が必要であり、リクエストされた操作の実行が接続ユーザーに認可されていることを常に確認します。認証に有効なユーザー名およびパスワードを指定する必要があります。
Oracle Database API for MongoDBでは、認証用に次の接続オプション値のみがサポートされています。
-
オプション
authMechanism
のPLAIN
値(プレーン・テキスト認証)。特に、SCRAM-SHA-*
認証方式はサポートされていません。 - オプション
authSource
の$external
値。(認証方式がPLAIN
の場合、MongoDBには常にこれが必要です。)
Oracle Database API for MongoDBは、Oracle Databaseのユーザー、権限およびロールを利用します。MongoDBクライアントまたはドライバを使用して、これらのユーザーおよびロールを追加または変更することはできません。かわりに、SQLまたはOracle Database Actionsを使用してこれを実行できます。APIを使用するために必要なOracle Databaseの最小ロールは、CONNECT
、RESOURCE
およびSODA_APP
です。
Oracle REST Data Services (ORDS)で使用する場合は、ユーザー(データベース・スキーマ)も有効にする必要があります。これは、PL/SQLプロシージャORDS.enable_schema
を呼び出すか、Oracle Database Actionsを使用して実行できます。
MongoDBの場合、データベースとはコレクションのセットのことです。Oracle Database API for MongoDBの場合、これはOracle Databaseのスキーマに対応します。
ノート:
Oracle API for MongoDBを使用してデータベースを削除しても、基礎となるデータベース・スキーマは削除されません。かわりに、スキーマ内のすべてのコレクションを削除します。
管理ユーザーは、SQLを使用してスキーマを削除できます(たとえば、Autonomous Oracle DatabaseでDatabase Actionsを使用します)。
APIの場合、ユーザー名はデータベース・スキーマ名である必要があります。この名前は大文字と小文字が区別されず、英字以外の文字(数字を含む)で開始できず、セキュアなパスワードを指定する必要があります。
APIのユーザーは、通常、そのスキーマ(ユーザー名はスキーマ名です)内でのみ操作を実行できます。このような操作の例として、新しいコレクションの作成、ドキュメントの読取りと書込み、索引の作成などがあります。
管理ユーザーが存在しないデータベース・スキーマ(ユーザー)にデータを挿入しようとすると、そのスキーマはスキーマ専用アカウントとして自動的に作成されます。つまり、パスワードがなく、ログインできません。新しいスキーマには、SODA_APP
、CREATE SESSION
、CREATE TABLE
、CREATE VIEW
、CREATE SEQUENCE
、CREATE PROCEDURE
およびCREATE JOB
の権限が付与されます。また、スキーマには無制限の表領域割当て容量も与えられ、Oracle REST Data Services (ORDS)を使用できるようになります。
APIの通常ユーザーの場合、現在のMongoDBデータベースを別のデータベースに切り替えるMongoDBシェル・コマンド(use <database>
など)は通常サポートされていません。別のデータベース・スキーマに切り替えると、エラーが発生します。
ただし、管理ユーザー(CREATE USER
、ALTER USER
、DROP USER
のいずれの権限も持つユーザー)は、新規ユーザー(データベース・スキーマ)を作成し、任意のユーザーとして任意のスキーマにアクセスできます。
管理ユーザーは、次の操作を実行できます。
-
他のユーザーのスキーマを使用します。
現在のユーザー以外のスキーマにアクセスする場合にプロキシ接続を使用できます。たとえば、管理ユーザーとして接続しているユーザーは、
other_user
として直接接続する場合と同じロールと権限を使用して、スキーマother_user
で操作を実行できます。 -
新規ユーザー(スキーマ)を作成します。
たとえば、まだ存在しないスキーマ
toto
に管理ユーザーがコレクションを作成しようとすると、そのスキーマ(ユーザー)が自動的に作成されます。
管理ユーザーの使用を本番アプリケーションでは許可しないことをお薦めします。かわりに、アプリケーションには通常のユーザーとして、最小限の権限で接続してください。特に、特定のスキーマ(ユーザー)に固有のMongoClientを使用して、データベースにアプリケーションを接続します。
関連トピック
関連項目:
-
Oracle Autonomous Database Serverlessの使用のAutonomous Databaseでのユーザーの作成
-
Oracle Autonomous Database Serverlessの使用のAutonomous Databaseでのユーザー・ロールおよび権限の管理
-
SQLを使用してデータベース・スキーマ(データベース・ユーザーとも呼ばれる)を作成する方法の詳細は、Oracle Database SQL言語リファレンスのCREATE USER
-
SQLを使用してロールをデータベース・スキーマに付与する方法の詳細は、Oracle Database SQL言語リファレンスのGRANT
-
Oracle Database API for MongoDBでのAutonomous Database (Autonomous JSON Databaseを含む)の使用の詳細は、Oracle Autonomous Database Serverlessの使用のOracle Database API for MongoDBの使用。ここでは、セキュリティや接続など、APIで使用するためのデータベースの構成について説明します。
-
ORDSでのデータベース・スキーマの有効化については、『Oracle REST Data Services開発者ガイド』のORDS.ENABLE_SCHEMAを参照してください
2.3 MongoDBからOracle Databaseへのアプリケーション・データの移行
JSONデータをMongoDBからエクスポートしてOracle Databaseにインポートする方法をいくつか説明します。移行に関する考慮事項について説明します。
次のいずれかの方法でアプリケーション・データを移行できます。
-
MongoDBコマンドライン・ツール
mongoexport
およびmongoimport
を使用します。mongoexport
はMongoDBインスタンスからファイル・システムにデータをエクスポートし、mongoimport
はエクスポートされたデータをファイル・システムからOracle Databaseにインポートします。mongoimport
を使用する場合は、データベース接続情報を指定します。例2-6にこれを示します。 -
CompassなどのMongoDBツールをOracle Databaseに接続した後、そのツールを使用してOracle Databaseにデータをインポートします。JSONコレクションの名前を選択し、「ADD DATA」を選択します。
これにより、コレクション・データが含まれているJSONファイルを参照してインポートするためのポップアップ・ダイアログ・ボックスが表示されます。MongoDB Compassを参照してください。
図mongodb_compass.pngの説明 -
JSONデータをファイル・システムにエクスポートした後、それをOracle Cloud Object Storeにインポートし、PL/SQLプロシージャ
DBMS_CLOUD.copy_collection
を使用してそこからコレクションにロードします。例2-7にこれを示します。これによりデータがパラレルで処理されるため、通常は
mongoimport
より高速です。 -
JSONドキュメントをMongoDBへの接続から読み取ってOracle Databaseへの接続に書き込むプログラムを記述します。
例2-6 mongoexportおよびmongoimportを使用したJSONデータのOracle Databaseへの移行
この例では、コレクションsales
をMongoDBからファイル・システム・ファイルsales.json
にエクスポートします。次に、そのファイルからOracle Databaseにコレクションsales
としてデータをインポートします。ユーザーは、データベース・スキーマ<user>
としてパスワード<password>
を使用してホスト<host>
に接続されています。
mongoexport --collection=sales --out sales.json
mongoimport 'mongodb://<user>:<password>@<host>:27017/<user>?authMechanism=PLAIN&authSource=$external&ssl=true' --collection=sales --file=sales.json
ノート:
URIパーセント・エンコーディングを使用して、接続文字列URIの任意の予約文字(特にユーザー名とパスワードの文字)を置換します。予約文字とそのパーセント・エンコーディングは次のとおりです。
! |
# |
$
|
% |
& |
'
|
( |
)
|
* |
+ |
---|---|---|---|---|---|---|---|---|---|
%21 |
%23 |
%24 |
%25 |
%26 |
%27 |
%28 |
%29 |
%2A |
%2B |
, |
/ |
:
|
; |
= |
?
|
@
|
[ |
] |
---|---|---|---|---|---|---|---|---|
%2C |
%2F |
%3A |
%3B |
%3D |
%3F |
%40 |
%5B |
%5D |
たとえば、ユーザー名がRUTH
で、パスワードが@least1/2#?
の場合、サーバー<server>
へのMongoDB接続文字列は次のようになります。
'mongodb://RUTH:%40least1%2F2%23%3F@<server>:27017/ruth/ ...'
使用するツールまたはドライバによっては、URI接続文字列の一部としてではなく、別のパラメータとしてユーザー名とパスワードを指定できる場合があります。その場合、含まれている予約文字をエンコードする必要はありません。
関連項目:
関連項目:
Oracle Database API for MongoDBでのAutonomous Database (Autonomous JSON Databaseを含む)の使用の詳細は、Oracle Autonomous Database Serverlessの使用のOracle Database API for MongoDBの使用。ここでは、セキュリティや接続など、APIで使用するためのデータベースの構成について説明します。
例2-7 DBMS_CLOUD.COPY_COLLECTIONを使用したコレクションへのJSONデータのロード
この例では、PL/SQLプロシージャDBMS_CLOUD.copy_collection
を使用して、Oracle Cloud Object Storeから新しいコレクションnewCollection
にデータをロードします。データはMongoDBからファイル・システムにエクスポートされ、そこからパラメータfile_uri_list
の値として渡されるオブジェクト・ストアの場所にインポートされたと想定しています。
copy_collection
パラメータFORMAT
として渡される値は、フィールドrecorddelimiter
およびtype
を持つJSONオブジェクトです。
-
フィールド
recorddelimiter
では、入力データのレコードを改行文字で区切ることを指定しています。レコードごと、つまり改行区切りの入力データ内の行ごとに1つのJSONドキュメントが作成されます。 -
フィールド
type
では、入力JSONデータにEJSON拡張オブジェクトを含めることができ、それらを解釈する必要があることを指定しています。
パラメータFORMAT
の詳細は、Oracle Autonomous Database Serverlessの使用のDBMS_CLOUDパッケージ・フォーマット・オプションを参照してください。
BEGIN
DBMS_CLOUD.copy_collection(
collection_name => 'newCollection',
file_uri_list => 'https://objectstorage.../data.json',
format => json_object(
'recorddelimiter' : '''\n''',
'type' : 'ejson'));
END;
/
関連項目:
-
PL/SQLプロシージャ
DBMS_CLOUD.COPY_COLLECTION
の使用の詳細は、Oracle Autonomous JSON Databaseの使用のコレクションへのJSONドキュメントの配列のロード
2.4 MongoDB集計パイプラインのサポート
Oracle Database API for MongoDBでは、MongoDB集計パイプライン、つまりMongoDBコマンドaggregate
がサポートされています。パイプライン・コードを使用して、一連の操作として問合せを実行できます。このプロシージャ型アプローチの宣言型の代替としてSQLを使用することもできます。
MongoDBの集計パイプラインは、基本的にSQL機能の部分的なエミュレーションです。MongoDBでは、ソート、グループ化、順序付けなどの操作をパイプラインの個別のステップとして表します。このアプローチはプロシージャ型です。問合せを一連の操作として実行する方法を指定します。
一方、SQLは宣言型です。必要な問合せ結果を指定すると、オプティマイザは、使用可能な索引、データ統計、コスト見積りなどに基づいて最適な実行プランを選択します。つまり、実行する処理を指定し、ユーザーではなくオプティマイザが実行すべき方法を決定します。
Oracle DatabaseによるJSONデータのSQLサポートには、ドキュメントやコレクションの操作、およびJSONデータとJSON以外のデータ(リレーショナル、空間、グラフなど)の結合が含まれます。Oracle Database API for MongoDBのユーザーとして、特定の操作を手動で指定および順序付けすることなく、SQLをJSONデータに直接適用できます。
ただし、MongoDB集計パイプライン・コードを使用する場合、MongoDB APIはパイプラインのステージおよび操作を同等のSQLコードに自動的に変換し、オプティマイザは可能なかぎり最適な実行プランを選択します。APIでは、MongoDB集計パイプラインのステージおよび操作のサブセットがサポートされています。詳細は、集計パイプライン演算子を参照してください。
MongoDBとは異なり、Oracle Databaseではソート、結合またはグループ化されるデータのサイズに制限がありません。任意の数のコレクションにわたる何百万ものドキュメントを対象としたレポート作業や分析作業に使用できます。
JSONデータのOracle Database簡易ドット表記法、または標準のSQL/JSONファンクションjson_value
、json_query
およびjson_table
を使用して、JSONデータからレポートや分析の目的で値を抽出できます。SQL/JSON生成ファンクションを使用して、リレーショナル・データおよびその他の種類のデータ(空間データやグラフ・データなど)をJSONデータに変換できます。1つのSQL FROM
句を使用して、複数の表およびコレクションにあるJSONデータを結合できます。
MongoDB集計パイプラインは、1つ以上のコレクションからJSONドキュメントに対して操作を実行します。これは、連続するステージで構成され、それぞれがドキュメント操作を実行し、結果のドキュメントを次のステージに渡してさらに処理します。どのステージの操作でも、前のステージから渡されたドキュメントをフィルタリングしたり、次のステージのために変換(更新)したり、新しいドキュメントを作成したりできます。変換には、複数のドキュメントのフィールド値を組み合せることができる$avg
(平均)などの集計演算子(アキュムレータとも呼ばれる)を使用できます。
パイプライン内の各ステージは、JSON値である集計式で表されます。詳細は、MongoDB集計パイプラインのドキュメントを参照してください。
宣言SQLコードを使用して、集計パイプラインを使用して行うことを実現できます。これは、Oracle Databaseパラメータcompatible
が23
より小さい場合に特に関連します。この場合、ほとんどのMongoDB集計パイプラインはサポートされていません。例2-8にこれを示します。
例2-8 MongoDB集計パイプライン・コードのかわりにSQLコードを使用
この例では、郵便番号別に平均売上を計算します。まず、これを実行するMongoDB集計パイプライン式を示し、次に、同等のSQLコードを示します。
MongoDB集計パイプライン:
次のコードは、結果の計算方法をMongoDBに指示します。これには実行順序が指定されています。
db.sales.aggregate(
[{"$group" : {"_id" : "$address.zip",
"avgRev" : {"$avg" : "$revenue"}}},
{"$sort" : {"avgRev" : -1}}])
SQL:
次のコードは、出力表現のグループ化と順序を宣言して指定します。実行順序など計算の実行方法は指定しません。簡単に言えば、結果は郵便番号別にグループ化され、平均収益値の降順で表示されます。問合せは、郵便番号(文字列)および平均収益(数値)のスカラー値が含まれる2列の行を返します。
SELECT s.data.address.zip.string(),
avg(s.data.revenue.number())
FROM sales s
GROUP BY s.data.address.zip.string()
ORDER BY 2 DESC;
次の問合せは似ていますが、結果がJSONオブジェクトの行となります。各行には、郵便番号を表す文字列フィールドzip
と、平均収益を表す数値フィールドavgRev
があります。SQL/JSON生成ファンクションjson_object
は、引数であるSQL式の評価結果からJSONオブジェクトを構成します。
SELECT json_object('zip' : s.data.address.zip.string(),
'avgRev' : avg(s.data.revenue.number()))
FROM sales s
GROUP BY s.data.address.zip.string()
ORDER BY avg(s.data.revenue.number()) DESC;
関連トピック
2.5 MongoDBドキュメントおよびOracle Database
ここでは、MongoDBで使用されるJSONドキュメントとOracle Databaseで格納され使用されるJSONドキュメントとの関係を示します。
ノート:
このトピックは、MongoDBから移行してOracle Databaseに格納するJSONドキュメントに当てはまります。JSONリレーショナル二面性ビューによって生成/サポートされるJSONドキュメントには当てはまりません。MongoDB互換の二面性ビューについては、Mongo DB APIとJSONリレーショナル二面性ビューの使用を参照してください。
既存のアプリケーションとそのデータをMongoDBからOracle Databaseに移行することも、MongoDB上のアプリケーションと同じまたは類似したデータを使用する新しいアプリケーションをOracle Database上で開発することもできます。どちらの場合も、JSONデータはドキュメントに格納されます。
MongoDBで使用されるドキュメントとOracle Databaseで使用されるドキュメントの相違点を全般的に理解しておくと便利です。特に、MongoDBドキュメントをOracle Databaseで使用できるようにするために、インポートするMongoDBドキュメントがどのように処理されるかを理解するために役立ちます。
ここに示す情報に含まれる詳細な内容は、概要を把握するためのみこのトピックを参照する場合には無視できます。ただし、記載内容を認識しておくと、将来必要に応じて参照するときに役立ちます。
MongoDBドキュメントのコレクションをインポートすると、各ドキュメントのキーおよびコンテンツがOracle Databaseに適したフォームに変換されます。
MongoDBドキュメントには、BSONというネイティブのバイナリJSON形式があります。Oracle Databaseドキュメントには、OSONというネイティブのバイナリJSON形式があります。したがって、MongoDBドキュメントに加えられる変更の1つに、そのバイナリ形式をBSONからOSONに変換するというものがあります。この変換は、ドキュメントのキーとコンテンツの両方に適用されます
ノート:
Oracle Database API for MongoDBの場合、MongoDB自体に関しては、ステージで入力が受信され、BSONデータ(つまり、MongoDB形式のバイナリJSONデータ)の形式で出力が生成されます。
ドキュメント・キー: 相違点と変換(23aiより前のOracle Database)
この項は、23aiより前のOracle Databaseリリースにのみ当てはまります。
MongoDBの場合、ドキュメントを識別する一意キーはドキュメント自体の必須フィールド_id
の値です。23aiより前のOrace Databaseリリースの場合、ドキュメントを識別する一意キーはドキュメントから分離され、キーはドキュメントを格納する列とは別のデータベース列に格納されます。キー列はid
という名前で、コレクション・データを格納する表の主キー列です。
23aiより前のOracle Databaseにコレクションをインポートすると、Oracle Database API for MongoDBによって、MongoDBドキュメント内のフィールド_id
の値からid
列の値が作成されます。MongoDBフィールド_id
には、複数の異なるデータ型の値を指定できます。そのフィールドに対応するOracle Databaseのid
列は、常にSQLデータ型VARCHAR2
(文字データ、つまり文字列)になります。
インポートしたドキュメントの_id
フィールドは、インポート中およびそれ以降変更されません。Oracle Databaseではこれは使用されず、かわりに列id
が使用されます。ただし、これも変更されないため、アプリケーションで任意にそのフィールドを使用することは引き続き可能です。ドキュメントのフィールド_id
が変更されることはありません。アプリケーションでも変更(削除または更新)できません。
SQLまたはSimplified Oracle Document Access (SODA)を使用してドキュメントを操作する必要がある場合は、列id
を直接使用できます。たとえば、その主キー列を使用すると、JSONデータを他のデータベース・データと簡単に結合できます。MongoDBからのインポートによって生成されるドキュメントはSODAドキュメントです(ネイティブ・バイナリOSONデータが含まれています)。
ドキュメントとドキュメント・キーの分離によってもたらされる次の考慮事項に注意してください。
-
MongoDBからインポートされたすべてのドキュメントには引き続き
_id
フィールドがありますが、23aiより前のOracle Databaseの場合、JSONコレクション内のドキュメントには_id
フィールドが必要ありません。また、23aiより前のOracle Databaseの場合、ドキュメントとそのキーは分離されているため、MongoDBからインポートされたドキュメント以外のドキュメントに、ドキュメント・キーとの関連がない_id
フィールドが含まれる可能性があります。 -
MongoDBでは様々なタイプの
_id
値が許可され、これらはすべて文字列値(VARCHAR2
)に変換されるため、なんらかの理由でコレクションに_id
値が"123"
(JSON文字列)および123
(JSON数値)のドキュメントが含まれている場合、そのコレクションをインポートすると、重複キー・エラーが発生します。これは、これらの列id
値がそれぞれ同じ文字列値に変換されるためです。
フィールド_id
のBSON値は、表2-1に従ってVARCHAR2
列のid
値に変換されます。_id
フィールド値が表にリストされていないタイプである場合は、生成されたObjectId
値に置き換えられた後、id
列値に変換されます。
表2-1 BSONフィールド_id値の列ID VARCHAR2値への変換
_idフィールド・タイプ | ID列VARCHAR2値 |
---|---|
Double |
標準的な数値形式文字列 |
32-bit integer |
標準的な数値形式文字列 |
64-bit integer |
標準的な数値形式文字列 |
Decimal128 |
標準的な数値形式文字列 |
String |
変換なし(文字のエスケープなしなど) |
ObjectId |
小文字の16進数文字列 |
Binary data (UUID)
|
小文字の16進数文字列 |
Binary data (UUID以外)
|
大文字の16進数文字列 |
VARCHAR2
値の標準的な数値形式は次のとおりです。
-
入力数値に小数部分がなく(整数)、40桁以下で表示できる場合は、整数として表示されます。必要に応じて、指数で表記されないように後続のゼロが使用されます。たとえば、
1E+9
ではなく1000000000
が使用されます。 -
入力数値に小数部がある場合、数値は小数点記号を使用して40桁以下で表示されます。必要に応じて、指数で表記されないようにするために、ゼロが使用されます。たとえば、
1E-5
ではなく0.00001
が使用されます。 -
入力数値を変換したときに、40桁の形式では桁精度が失われる場合は、かわりに数値が指数で表示されます。これは、数値が整数であっても、絶対値が非常に小さいか非常に大きい数値の場合に発生する可能性があります。たとえば、1の後にゼロが100個続くことを避けて
1E100
が使用されます。
実際、この標準的な数値形式では、ほとんどの場合、列id
に対して数値の_id
フィールド値は見やすく整形されたVARCHAR2
値になります。指数を使用する形式は、必要な場合にのみ使用され、通常頻繁には使用されません。
ドキュメント・コンテンツ変換
2つの一般的な考慮事項:
-
BSON形式では、同じオブジェクト内でフィールド値の重複が許可されます。OSON形式では許可されません。OSONに変換する場合、BSONデータで重複フィールドが検出されるとエラーが発生します。
-
OSON形式では、オブジェクト内のフィールドの順序が認識されません。アプリケーションが(JSON標準に準拠して)特定の順序に依存したり、特定の順序を想定することはできません。BSON形式は、オブジェクト・フィールドの順序を維持します。アプリケーションでは順序が変更されないことに依存できます。
表2-2に、スカラーBSONデータをスカラーOSONデータに変換する際に適用される型マッピングを示します。使用されるOSONスカラー型は、特に記述されていないかぎり、SQLデータ型です。リストされていないBSON型は変換されません。かわりに、それが検出されるとエラーになります。これには、BSON型regex
やJavaScript
などがあります。
表2-2 JSONスカラー型変換: BSONからOSON形式
BSON型 | OSON型脚注2 | ノート |
---|---|---|
Double |
BINARY_DOUBLE |
NA |
32-bit integer |
NUMBER (Oracleの数値)
|
int のフラグが付けられます。
|
64-bit integer |
NUMBER (Oracleの数値)
|
long のフラグが付けられます。
|
Decimal128 |
NUMBER (Oracleの数値)
|
decimal のフラグが付けられます。ノート: この変換は失われる可能性があります。 |
Date |
TIMESTAMP WITH TIME ZONE |
常にUTCタイムゾーン。 |
String |
VARCHAR2 |
常に文字セットAL32UTF8 (Unicode UTF-8)になります。 |
Boolean |
BOOLEAN |
初期化パラメータcompatible の値が23 以上の場合のみサポートされます。(23aiより前のリリースでは、Oracle SQLのBOOLEAN 型はありません。)
|
ObjectId |
ID (RAW(12) )
|
NA |
Binary data (UUID)
|
ID (RAW(16) )
|
NA |
Binary data (UUID以外)
|
RAW |
NA |
Null |
NULL |
JSON null に使用されます。
|
脚注2 これらは、特に記述されていないかぎり、SQLデータ型です。
関連項目:
-
Oracle Database Simple Oracle Document Access (SODA)の概要のSODAドキュメントの概要
-
BSON型(MongoDB)
-
データ型(MongoDBシェル)
2.6 MongoDBとOracle Databaseとのその他の相違点
MongoDBとOracle Databaseとの様々な相違点について説明します。これらの相違点には、通常、他のトピックでは触れていません。アプリケーションをOracle Databaseに移行する場合や、MongoDBコマンドを使用するOracle Database向けの新しいアプリケーションを開発する場合に、これらの相違点を考慮してください。
-
MongoDBでは、JSONオブジェクトのフィールドが順序付けられます。Oracle Databaseでは順序付けられません。たとえば、フィールド
_id
は必ずしもオブジェクトの最初のフィールドではありません。アプリケーションでは、特定のフィールド順序を想定したり、その順序に依存しないようにする必要があります。JSON言語標準では、オブジェクト・フィールドは順序付けされず、配列要素のみが順序付けされます。Oracle Database JSON開発者ガイドのJSONの構文とそれで表されるデータを参照してください。 -
MongoDBでは、フィールド
_id
の値をJSONオブジェクトにすることができます。Oracle Database API for MongoDBでは、フィールド_id
にObjectId
、String
、Double
、32-bit integer
、64-bit integer
、Decimal128
、Binary data
(UUIDのサブタイプ)の各BSON型のみがサポートされています。他の型にするとエラーが発生します。BSON型を参照してください。_id
のオブジェクト値を必要とする既存のアプリケーションを移行する場合は、データ内のフィールド_id
の値を新しいフィールドにコピーし、_id
の文字列値を使用することを検討してください。 -
MongoDBトランザクションに関する読取りおよび書込みの問題は、Oracle Databaseには該当しません。Oracle DatabaseトランザクションはACIDに完全に準拠しているため、信頼性(原子性、一貫性、分離および永続性)があります。ACID準拠により、トランザクションの処理中に障害が発生しても、データの正確性と一貫性が保たれます。
-
Oracle API for MongoDBは、次のMongoDBトランザクション機能をサポートしていません。
-
トランザクション内に
createCollection
などのDDL操作を含めること。トランザクション内にコレクションまたは索引を作成しようとすると、エラーが発生します。 -
複数のデータベースにまたがる操作を含めること。トランザクション内のすべての操作は、単一のデータベース(スキーマ)に限定する必要があります。そうしないと、エラーが発生します。
-
-
エラー発生時に再試行可能な書込みまたはコミット。
MongoDBで
retryWrite
操作を行うとエラーが発生します。デフォルトでretryWrite
がオンになっているドライバを使用する場合は、接続文字列にretryWrites=false
を設定してオフにしてください。 -
Oracle DatabaseとMongoDBでは、読取り分離レベルと一貫性レベルが異なります。Oracle Database API for MongoDBでは、Oracle Databaseの概要のデータの同時実行性と整合性で説明されているように、読取りコミットの一貫性を使用します。
-
Oracle Database API for MongoDBは、PLAIN (LDAP SASL)認証メカニズムのみをサポートし、Oracle Databaseの認証および認可に依存します。
-
Oracle Databaseでは、コマンド(
find
など)のMongoDBcollation
フィールドはサポートされません。フィールドcollation
を使用すると、エラーが発生します。Unicodeバイナリ照合順序を使用して値が照合されます。 -
MongoDBでは、同じデータベース内の複数の異なるコレクションに同じ名前の索引を使用できます。これはOracle Databaseでは許可されません。索引の名前は、特定のデータベース・スキーマ(データベース)のすべてのコレクションで一意である必要があります。
-
MongoDBのドキュメントの最大サイズは16 MBです。Oracle Databaseの場合(したがってMongoDB APIの場合)、最大サイズは32 MBです。
2.7 他のユーザー(データベース・スキーマ)が所有するコレクションへのアクセス
そのスキーマにログインすると、別のユーザー(データベース・スキーマ)が所有するMongoDB APIコレクションに直接アクセスできます。そのコレクションが自分のスキーマ内のコレクションにマップされている場合は、そのスキーマにログインせずに、別のユーザーが所有するコレクションに間接的にアクセスできます。
JSONドキュメントのMongoDB APIコレクションは、(1)コレクション内のJSONドキュメントを含むコレクション・バッキング表と、(2)データ・ディクショナリに格納され、様々なコレクション構成プロパティを指定する、JSON形式のコレクション・メタデータで構成されます。バッキング表は、指定されたデータベース・ユーザー/スキーマに属しています。メタデータはデータベース・データ・ディクショナリに格納されます。
マップされたコレクションは、既存の表に加えて定義(マップ)されるコレクションで、任意のデータベース・スキーマに属し、他の1つ以上のコレクションを補足することもできます。
バッキング表に対する異なる権限またはロールを様々なユーザーに付与することで、コレクション(マップされたコレクションを含む)に対するどの操作をそれらのユーザー(スキーマ)に対して許可するかを制御できます。
例2-9にこれを示します。
例2-9 あるスキーマでコレクションを作成し、別のスキーマでそのコレクションに1つのコレクションをマッピング
この例では、ユーザーjohn
はコレクションjohn_coll
を(データベース・スキーマjohn
に)作成し、そのコレクションにドキュメントを追加します。次に、ユーザーjohn
は、コレクションjohn_coll
のバッキング表に対するいくつかのアクセス権限をユーザーjanet
に付与します。
次に、ユーザーjanet
は、新しいコレクションjanet_coll
を(スキーマjanet
で)スキーマjohn
のコレクションjohn_coll
にマップします。(元のコレクションとマップされたコレクションは、異なる名前(john_coll
とjanet_coll
など)を持つ必要はありません。両方とも同じ名前を持つことができます。)
次に、ユーザーjanet
は、スキーマjanet
で使用可能なコレクションをリストし、マップされたコレクションjanet_coll
のコンテンツを読み取ります。このコンテンツは、コレクションjohn_coll
のコンテンツと同じです。
(mongosh
に送信されるコマンドはそれぞれ1行(文字列)ですが、わかりやすくするために、ここでは複数行にわたって続けて表示しています。)
ノート:
Oracle Database API for MongoDBへの入力およびそこからの出力の例では、シェルmongosh
の構文を使用します。
1.ユーザーjohn
としてデータベースに接続している場合は、PL/SQLコードを実行して、表john_coll
に基づくコレクションjohn_coll
を作成します。create_collection
の2番目の引数は、MongoDB互換コレクションに必要なメタデータです。(バッキング表名はコレクション名から導出されます。コレクション表のデフォルトのネーミングを参照してください。)
DECLARE
col SODA_COLLECTION_T;
BEGIN
col := DBMS_SODA.create_collection(
'john_coll',
'{"contentColumn" : {"name" : "DATA",
"sqlType" : "BLOB",
"jsonFormat" : "OSON"},
"keyColumn" : {"name" : "ID",
"assignmentMethod" : "EMBEDDED_OID",
"sqlType" : "VARCHAR2"},
"versionColumn" : {"name" : "VERSION", "method" : "UUID"},
"lastModifiedColumn" : {"name" : "LAST_MODIFIED"},
"creationTimeColumn" : {"name" : "CREATED_ON"}}');
END;
2.ユーザーjohn
としてシェルmongosh
を使用してデータベースに接続し、そのスキーマ内のコレクション(Johnのコレクション)をリストし、コレクションjohn_coll
にドキュメントを挿入して、挿入の結果を表示します。
mongosh 'mongodb://john:...
@MQSSYOWMQVGAC1Y-CTEST.adb.us-ashburn-1.oraclecloudapps.com:27017/john
?authMechanism=PLAIN&authSource=$external&ssl=true&retryWrites=false&loadBalanced=true'
john> show collections;
出力:
john_coll
john> db.john_coll.insert({"hello" : "world"});
john> db.john_coll.find()
出力:
[ { _id: ObjectId("6318b0060a51240e4bf3b001"), hello: 'world' } ]
3.スキーマjohn
で、コレクションjohn_coll
および同じ名前のバッキング表john_coll
に対するアクセス権限をユーザーjanet
に付与します。
GRANT SELECT, INSERT, UPDATE, DELETE ON john.john_coll TO janet;
4.ユーザー(スキーマ)janet
としてデータベースに接続している場合は、スキーマjanet
内に新しいコレクションjanet_coll
を作成します。このコレクションは、スキーマjohn
内のコレクションjohn_coll
にマップされます。
メソッドcreate_collection()
の2番目の引数はコレクション・メタデータです。ここでは、マップ先のコレクションのスキーマ名とバッキング表名を指定します。最後の引数CREATE_MODE_MAP
は、元のコレクションを補足する表に加えて、新しいコレクションがマップされることを指定します。
DECLARE
col SODA_COLLECTION_T;
BEGIN
col := DBMS_SODA.create_collection(
'janet_coll',
'{"schemaName" : "JOHN",
"tableName" : "JOHN_COLL",
"contentColumn" : {"name" : "DATA",
"sqlType" : "BLOB",
"jsonFormat" : "OSON"},
"keyColumn" : {"name" : "ID",
"assignmentMethod" : "EMBEDDED_OID",
"sqlType" : "VARCHAR2"},
"versionColumn" : {"name" : "VERSION", "method" : "UUID"},
"lastModifiedColumn" : {"name" : "LAST_MODIFIED"},
"creationTimeColumn" : {"name" : "CREATED_ON"}}',
DBMS_SODA.CREATE_MODE_MAP);
END;
ノート:
コレクション・メタデータ引数で使用されるスキーマ名および表名は、データ・ディクショナリに表示されるとおりである必要があります。この場合、大文字である必要があります。次の問合せを使用して、コレクション<collection>
の正しいスキーマ名および表名を取得できます(<collection>
の所有者として接続されている場合)。
SELECT c.json_descriptor.schemaName FROM USER_SODA_COLLECTIONS c
WHERE uri_name = '<collection>';
SELECT c.json_descriptor.tableName FROM USER_SODA_COLLECTIONS c
WHERE uri_name = '<collection>';
5.ユーザーjanet
としてシェルmongosh
を使用してデータベースに接続し、使用可能なコレクションをリストし、コレクションjanet_coll
のコンテンツ(Johnのコレクションjohn_coll
のコンテンツと同じ)を表示します。
mongosh 'mongodb://janet:...
@MQSSYOWMQVGAC1Y-CTEST.adb.us-ashburn-1.oraclecloudapps.com:27017/janet
?authMechanism=PLAIN&authSource=$external&ssl=true&retryWrites=false&loadBalanced=true'
janet> show collections;
janet_coll
janet> db.janet_coll.find()
[ { _id: ObjectId("6318b0060a51240e4bf3b001"), hello: 'world' } ]
脚注の説明
脚注1: MongoDBではコンポジット索引を複合索引と呼びます。コンポジット索引は、連結索引とも呼ばれます。