227.5. MongoDB 操作 - プロデューサーエンドポイント

227.5.1. クエリー操作

227.5.1.1. findById

この操作は、_id フィールドが IN メッセージ本文の内容と一致するコレクションから 1 つの要素のみを取得します。着信オブジェクトは、BSON 型と同等のものであれば何でもかまいません。http://bsonspec.org//specification[http://bsonspec.org//specification] および http://www.mongodb.org/display/DOCS/Java+Types を参照してください。

from("direct:findById")
    .to("mongodb:myDb?database=flights&collection=tickets&operation=findById")
    .to("mock:resultFindById");
ヒント

オプションのパラメーターをサポートします。この操作は、フィールドフィルターの指定をサポートします。オプションのパラメーターの指定 を参照してください。

227.5.1.2. findOneByQuery

この操作を使用して、MongoDB クエリーに一致するコレクションから要素を 1 つだけ取得します。クエリーオブジェクトは、IN メッセージボディーから抽出されます。つまり、DBObject タイプであるか、DBObject に変換可能である必要があります。JSON 文字列または Hashmap にすることができます。詳細については、#型変換 を参照してください。

クエリーのない例 (コレクションの任意のオブジェクトを返します):

from("direct:findOneByQuery")
    .to("mongodb:myDb?database=flights&collection=tickets&operation=findOneByQuery")
    .to("mock:resultFindOneByQuery");

クエリーのある例 (一致する結果を 1 つ返します):

from("direct:findOneByQuery")
    .setBody().constant("{ \"name\": \"Raul Kripalani\" }")
    .to("mongodb:myDb?database=flights&collection=tickets&operation=findOneByQuery")
    .to("mock:resultFindOneByQuery");
ヒント

オプションのパラメーターをサポートします。この操作は、フィールドフィルターおよび/または並べ替え句の指定をサポートします。オプションのパラメーターの指定 を参照してください。

227.5.1.3. findAll

findAll オペレーションは、クエリーに一致するすべてのドキュメントを返すか、またはまったく一致しないドキュメントを返します。この場合、コレクションに含まれるすべてのドキュメントが返されます。クエリーオブジェクトは、IN メッセージボディーから抽出されます。つまり、DBObject タイプであるか、DBObject に変換可能である必要があります。JSON 文字列または Hashmap にすることができます。詳細については、#型変換 を参照してください。

クエリーのない例 (コレクション内のすべてのオブジェクトを返します):

from("direct:findAll")
    .to("mongodb:myDb?database=flights&collection=tickets&operation=findAll")
    .to("mock:resultFindAll");

クエリーのある例 (一致するすべての結果を返します):

from("direct:findAll")
    .setBody().constant("{ \"name\": \"Raul Kripalani\" }")
    .to("mongodb:myDb?database=flights&collection=tickets&operation=findAll")
    .to("mock:resultFindAll");

ページングと効率的な検索は、次のヘッダーを介してサポートされています。

ヘッダーのキークイック定数説明 (MongoDB API ドキュメントから抜粋)想定されるタイプ

CamelMongoDbNumToSkip

MongoDbConstants.NUM_TO_SKIP

カーソルの先頭にある指定された数の要素を破棄します。

int/Integer

CamelMongoDbLimit

MongoDbConstants.LIMIT

返される要素の数を制限します。

int/Integer

CamelMongoDbBatchSize

MongoDbConstants.BATCH_SIZE

1 つのバッチで返される要素の数を制限します。通常、カーソルは結果オブジェクトのバッチをフェッチし、ローカルに保存します。batchSize が正の場合、取得されたオブジェクトの各バッチのサイズを表します。パフォーマンスを最適化し、データ転送を制限するように調整できます。batchSize が負の場合、最大バッチサイズ制限 (通常は 4MB) 内に収まる数のオブジェクトが返され、カーソルが閉じられます。たとえば、batchSize が -10 の場合、サーバーは最大 10 個のドキュメントを 4MB に収まる数だけ返し、カーソルを閉じます。この機能は、ドキュメントが最大サイズ内に収まる必要があるという点で limit() とは異なり、サーバー側でカーソルを閉じる要求を送信する必要がないことに注意してください。バッチサイズは、カーソルが反復された後でも変更できます。その場合、設定は次のバッチ取得に適用されます。

int/Integer

上記のヘッダーを設定するよりも簡単なエンドポイントオプションとして outputType=DBCursor (Camel 2.16+) を含めることで、サーバーから返されたドキュメントをルートにストリーミングすることもできます。これにより、Mongo シェル内で findAll() を実行しているかのように、Mongo ドライバーから Exchange に DBCursor が渡され、ルートが結果を反復できるようになります。デフォルトでは、このオプションを指定しないと、このコンポーネントはドキュメントをドライバーのカーソルから List にロードし、これをルートに返します。これにより、多数のメモリー内オブジェクトが発生する可能性があります。DBCursor では、一致したドキュメントの数を問い合わせないでください。詳細については、MongoDB ドキュメントサイトを参照してください。

オプション outputType=DBCursor およびバッチサイズの例:

from("direct:findAll")
    .setHeader(MongoDbConstants.BATCH_SIZE).constant(10)
    .setBody().constant("{ \"name\": \"Raul Kripalani\" }")
    .to("mongodb:myDb?database=flights&collection=tickets&operation=findAll&outputType=DBCursor")
    .to("mock:resultFindAll");

ページングを使用している場合、findAll 操作は次の OUT ヘッダーも返し、結果ページを反復処理できるようにします。

ヘッダーのキークイック定数説明 (MongoDB API ドキュメントから抜粋)データのタイプ

CamelMongoDbResultTotalSize

MongoDbConstants.RESULT_TOTAL_SIZE

クエリーに一致するオブジェクトの数。これは、制限/スキップを考慮していません。

int/Integer

CamelMongoDbResultPageSize

MongoDbConstants.RESULT_PAGE_SIZE

クエリーに一致するオブジェクトの数。これは、制限/スキップを考慮していません。

int/Integer

ヒント

オプションのパラメーターをサポートします。この操作は、フィールドフィルターおよび/または並べ替え句の指定をサポートします。オプションのパラメーターの指定 を参照してください。

227.5.1.4. count

コレクション内のオブジェクトの総数を返し、OUT メッセージ本文として Long を返します。
次の例では、dynamicCollectionName コレクション内のレコード数をカウントします。動的性が有効になっていることに注意してください。その結果、操作は "notableScientists" コレクションではなく、"dynamicCollectionName" コレクションに対して実行されます。

// from("direct:count").to("mongodb:myDb?database=tickets&collection=flights&operation=count&dynamicity=true");
Long result = template.requestBodyAndHeader("direct:count", "irrelevantBody", MongoDbConstants.COLLECTION, "dynamicCollectionName");
assertTrue("Result is not of type Long", result instanceof Long);

Camel 2.14 以降では、メッセージボディーで com.mongodb.DBObject オブジェクトをクエリーとして提供できます。操作は、この条件に一致するドキュメントの量を返します。 

 

DBObject query = ...
Long count = template.requestBodyAndHeader("direct:count", query, MongoDbConstants.COLLECTION, "dynamicCollectionName");

227.5.1.5. フィールドフィルターの指定 (プロジェクション)

デフォルトでは、クエリー操作は、一致するオブジェクト全体を (すべてのフィールドとともに) 返します。ドキュメントが大きく、フィールドのサブセットのみを取得する必要がある場合は、関連する DBObject (または JSON 文字列、マップなどの DBObject に変換可能な型) を設定するだけで、すべてのクエリー操作でフィールドフィルターを指定できます。) CamelMongoDbFieldsFilter ヘッダーの定数ショートカット: MongoDbConstants.FIELDS_FILTER

以下は、MongoDB の BasicDBObjectBuilder を使用して DBObject の作成を簡素化する例です。_idboringField を除くすべてのフィールドを取得します。

// route: from("direct:findAll").to("mongodb:myDb?database=flights&collection=tickets&operation=findAll")
DBObject fieldFilter = BasicDBObjectBuilder.start().add("_id", 0).add("boringField", 0).get();
Object result = template.requestBodyAndHeader("direct:findAll", (Object) null, MongoDbConstants.FIELDS_FILTER, fieldFilter);

227.5.1.6. ソート句の指定

特定のフィールドによるソートに基づいて、コレクションから最小/最大レコードを取得する必要があることがよくあります。Mongo では、操作は次のような構文を使用して実行されます。

db.collection.find().sort({_id: -1}).limit(1)
// or
db.collection.findOne({$query:{},$orderby:{_id:-1}})

Camel ルートでは、SORT_BY ヘッダーを findOneByQuery 操作で使用して、同じ結果を得ることができます。FIELDS_FILTER ヘッダーも指定されている場合、操作は、別のコンポーネント (たとえば、パラメーター化された MyBatis SELECT クエリー) に直接渡すことができる単一のフィールド/値のペアを返します。この例では、コレクションから一時的に最新のドキュメントをフェッチし、結果を documentTimestamp フィールドに基づいて 1 つのフィールドに削減する方法を示します。

.from("direct:someTriggeringEvent")
.setHeader(MongoDbConstants.SORT_BY).constant("{\"documentTimestamp\": -1}")
.setHeader(MongoDbConstants.FIELDS_FILTER).constant("{\"documentTimestamp\": 1}")
.setBody().constant("{}")
.to("mongodb:myDb?database=local&collection=myDemoCollection&operation=findOneByQuery")
.to("direct:aMyBatisParameterizedSelect")
;

227.5.2. 操作の作成/更新

227.5.2.1. insert

IN メッセージ本文から取得した新しいオブジェクトを MongoDB コレクションに挿入します。DBObject または List に変換するために型変換が試行されます。
シングル挿入とマルチ挿入の 2 つのモードがサポートされています。複数の挿入の場合、エンドポイントは、DBObject である、または DBObject に変換できる限り、任意のタイプのオブジェクトのリスト、配列、またはコレクションを期待します。すべてのオブジェクトが一度に挿入されます。エンドポイントは、入力に応じて、呼び出すバックエンド操作 (単一または複数の挿入) をインテリジェントに決定します。

例:

from("direct:insert")
    .to("mongodb:myDb?database=flights&collection=tickets&operation=insert");

オペレーションは WriteResult を返します 。WriteConcern または invokeGetLastError オプションの値に応じて、getLastError() がすでに呼び出されているかどうかが決まります。書き込み操作の最終的な結果にアクセスする場合は、WriteResultgetLastError() または getCachedLastError() を呼び出して CommandResult を取得する必要があります。次に、CommandResult.ok()CommandResult.getErrorMessage() および/または CommandResult.getException() を呼び出して結果を確認できます。

新しいオブジェクトの _id はコレクション内で一意である必要があることに注意してください。値を指定しない場合、MongoDB が自動的に値を生成します。ただし、指定しても一意でない場合、挿入操作は失敗します (Camel が気付くには、invokeGetLastError を有効にするか、書き込み結果を待機する WriteConcern を設定する必要があります)。

これはコンポーネントの制限ではありませんが、MongoDB でより高いスループットを実現する方法です。カスタム _id を使用している場合は、アプリケーションレベルで一意であることを確認する必要があります (これも良い方法です)。

Camel 2.15 以降: 挿入されたレコードの OID は、CamelMongoOid キー (MongoDbConstants.OID 定数) の下のメッセージヘッダーに格納されます。保存される値は、単一の挿入の場合は org.bson.types.ObjectId、複数のレコードが挿入された場合は java.util.List<org.bson.types.ObjectId> です。

227.5.2.2. save

保存操作は upsert (UPdate、inSERT) 操作と同等で、レコードが更新され、レコードが存在しない場合は挿入されます。これらはすべて 1 つのアトミック操作で行われます。MongoDB は _id フィールドに基づいてマッチングを実行します。

更新の場合、オブジェクトは完全に置き換えられ、MongoDB の $modifiers の使用は許可されないことに注意してください。したがって、オブジェクトがすでに存在する場合にそのオブジェクトを操作する場合は、次の 2 つのオプションがあります。

  1. 最初にオブジェクト全体とそのすべてのフィールドを取得するためのクエリーを実行し (効率的でない場合があります)、Camel 内で変更してから保存します。
  2. $modifiers で更新操作を使用すると、代わりにサーバー側で更新が実行されます。upsert フラグを有効にできます。この場合、挿入が必要な場合、MongoDB は $modifiers をフィルタークエリーオブジェクトに適用し、結果を挿入します。

以下に例を示します。

from("direct:insert")
    .to("mongodb:myDb?database=flights&collection=tickets&operation=save");

227.5.2.3. update

コレクションの 1 つまたは複数のレコードを更新します。正確に 2 つの要素を含む IN メッセージ本文として List<DBObject> が必要です。

  • 要素 1 (インデックス 0) ⇒ フィルタークエリー ⇒ 通常のクエリーオブジェクトと同じように、影響を受けるオブジェクトを決定します
  • 要素 2 (インデックス 1) ⇒ 更新ルール ⇒ 一致したオブジェクトがどのように更新されるか。MongoDB からのすべての 修飾子操作 がサポートされています。
注記

マルチアップデート。デフォルトでは、MongoDB は、複数のオブジェクトがフィルタークエリーに一致する場合でも、1 つのオブジェクトのみを更新します。一致する すべての レコードを更新するように MongoDB に指示するには、CamelMongoDbMultiUpdate IN メッセージヘッダーを true に設定します。

キー CamelMongoDbRecordsAffected を持つヘッダーが返されます (MongoDbConstants.RECORDS_AFFECTED 定数) 更新されたレコードの数 (WriteResult.getN() からコピーされます)。

次の IN メッセージヘッダーをサポートします。

ヘッダーのキークイック定数説明 (MongoDB API ドキュメントから抜粋)想定されるタイプ

CamelMongoDbMultiUpdate

MongoDbConstants.MULTIUPDATE

一致するすべてのオブジェクトに更新を適用する必要がある場合。http://www.mongodb.org/display/DOCS/Atomic+Operations を参照してください。

boolean/Boolean

CamelMongoDbUpsert

MongoDbConstants.UPSERT

存在しない場合にデータベースが要素を作成する必要があるかどうか

boolean/Boolean

たとえば、次の例では、"scientist" フィールドの値を "Darwin" に設定することで、filterField フィールドが true に等しい すべての レコードを更新します。

// route: from("direct:update").to("mongodb:myDb?database=science&collection=notableScientists&operation=update");
DBObject filterField = new BasicDBObject("filterField", true);
DBObject updateObj = new BasicDBObject("$set", new BasicDBObject("scientist", "Darwin"));
Object result = template.requestBodyAndHeader("direct:update", new Object[] {filterField, updateObj}, MongoDbConstants.MULTIUPDATE, true);

227.5.3. 操作の削除

227.5.3.1. remove

コレクションから一致するレコードを削除します。IN メッセージ本文は、削除フィルタークエリーとして機能し、DBObject タイプまたはそれに変換可能なタイプであることが期待されます。
次の例では、科学データベースの notableScientists コレクションで、フィールド 'conditionField' が true に等しいすべてのオブジェクトを削除します。

// route: from("direct:remove").to("mongodb:myDb?database=science&collection=notableScientists&operation=remove");
DBObject conditionField = new BasicDBObject("conditionField", true);
Object result = template.requestBody("direct:remove", conditionField);

キー CamelMongoDbRecordsAffected を持つヘッダーが返されます (MongoDbConstants.RECORDS_AFFECTED 定数)。タイプは int で、削除された (WriteResult.getN() からコピーされた) レコードの数を含みます。

227.5.4. 一括書き込み操作

227.5.4.1. bulkWrite

Camel 2.21 以降で利用可能

実行順序を制御して書き込み操作を一括で実行します。挿入、更新、および削除操作のコマンドを含む IN メッセージ本文として List<WriteModel<DBObject>> が必要です。

次の例では、新しい科学者 "Pierre Curie" を挿入し、"scientist" フィールドの値を "Marie Curie" に設定して ID "5" のレコードを更新し、ID "3" のレコードを削除します。

// route: from("direct:bulkWrite").to("mongodb:myDb?database=science&collection=notableScientists&operation=bulkWrite");
List<WriteModel<DBObject>> bulkOperations = Arrays.asList(
            new InsertOneModel<>(new BasicDBObject("scientist", "Pierre Curie")),
            new UpdateOneModel<>(new BasicDBObject("_id", "5"),
                                 new BasicDBObject("$set", new BasicDBObject("scientist", "Marie Curie"))),
            new DeleteOneModel<>(new BasicDBObject("_id", "3")));

BulkWriteResult result = template.requestBody("direct:bulkWrite", bulkOperations, BulkWriteResult.class);

デフォルトでは、操作は順番に実行され、最初の書き込みエラーで中断され、リスト内の残りの書き込み操作は処理されません。リスト内の残りの書き込み操作の処理を続行するように MongoDB に指示するには、CamelMongoDbBulkOrdered IN メッセージヘッダーを false に設定します。順序付けされていない操作は並行して実行され、この動作は保証されません。

ヘッダーのキークイック定数説明 (MongoDB API ドキュメントから抜粋)想定されるタイプ

CamelMongoDbBulkOrdered

MongoDbConstants.BULK_ORDERED

順序付きまたは順序なしの操作実行を実行します。デフォルトは true です。

boolean/Boolean

227.5.5. その他の操作

227.5.5.1. aggregate

Camel 2.14 から利用可能

本文に含まれる特定のパイプラインを使用して集計を実行します。集約は、長く重い操作になる可能性があります。注意して使用してください。

// route: from("direct:aggregate").to("mongodb:myDb?database=science&collection=notableScientists&operation=aggregate");
from("direct:aggregate")
    .setBody().constant("[{ $match : {$or : [{\"scientist\" : \"Darwin\"},{\"scientist\" : \"Einstein\"}]}},{ $group: { _id: \"$scientist\", count: { $sum: 1 }} } ]")
    .to("mongodb:myDb?database=science&collection=notableScientists&operation=aggregate")
    .to("mock:resultAggregate");

次の IN メッセージヘッダーをサポートします。

ヘッダーのキークイック定数説明 (MongoDB API ドキュメントから抜粋)想定されるタイプ

CamelMongoDbBatchSize

MongoDbConstants.BATCH_SIZE

バッチごとに返すドキュメントの数を設定します。

int/Integer

CamelMongoDbAllowDiskUse

MongoDbConstants.ALLOW_DISK_USE

集約パイプラインステージを有効にして、データを一時ファイルに書き込みます。

boolean/Boolean

outputType=DBCursor を使用すると、効率的な取得がサポートされます。

上記のヘッダーを設定するよりも簡単なエンドポイントオプションとして outputType=DBCursor (Camel 2.21+) を含めることで、サーバーから返されたドキュメントをルートにストリーミングすることもできます。これにより、Mongo シェル内で aggregate() を実行しているかのように、Mongo ドライバーから Exchange に DBCursor が渡され、ルートが結果を反復できるようになります。デフォルトでは、このオプションを指定しないと、このコンポーネントはドキュメントをドライバーのカーソルから List にロードし、これをルートに返します。これにより、多数のメモリー内オブジェクトが発生する可能性があります。DBCursor では、一致したドキュメントの数を問い合わせないでください。詳細については、MongoDB ドキュメントサイトを参照してください。

オプション outputType=DBCursor およびバッチサイズの例:

// route: from("direct:aggregate").to("mongodb:myDb?database=science&collection=notableScientists&operation=aggregate");
from("direct:aggregate")
    .setHeader(MongoDbConstants.BATCH_SIZE).constant(10)
    .setBody().constant("[{ $match : {$or : [{\"scientist\" : \"Darwin\"},{\"scientist\" : \"Einstein\"}]}},{ $group: { _id: \"$scientist\", count: { $sum: 1 }} } ]")
    .to("mongodb:myDb?database=science&collection=notableScientists&operation=aggregate&outputType=DBCursor")
    .to("mock:resultAggregate");

227.5.5.2. getDbStats

MongoDB シェルで db.stats() コマンドを実行するのと同じです。これは、データベースに関する有用な統計値を表示します。
以下に例を示します。

> db.stats();
{
    "db" : "test",
    "collections" : 7,
    "objects" : 719,
    "avgObjSize" : 59.73296244784423,
    "dataSize" : 42948,
    "storageSize" : 1000058880,
    "numExtents" : 9,
    "indexes" : 4,
    "indexSize" : 32704,
    "fileSize" : 1275068416,
    "nsSizeMB" : 16,
    "ok" : 1
}

使用例:

// from("direct:getDbStats").to("mongodb:myDb?database=flights&collection=tickets&operation=getDbStats");
Object result = template.requestBody("direct:getDbStats", "irrelevantBody");
assertTrue("Result is not of type DBObject", result instanceof DBObject);

この操作は、シェルに表示されるものと同様のデータ構造を、OUT メッセージ本文の DBObject の形式で返します。

227.5.5.3. getColStats

コレクションに関する有用な統計値を表示する、MongoDB シェルで db.collection.stats() コマンドを実行するのと同じです。
以下に例を示します。

> db.camelTest.stats();
{
    "ns" : "test.camelTest",
    "count" : 100,
    "size" : 5792,
    "avgObjSize" : 57.92,
    "storageSize" : 20480,
    "numExtents" : 2,
    "nindexes" : 1,
    "lastExtentSize" : 16384,
    "paddingFactor" : 1,
    "flags" : 1,
    "totalIndexSize" : 8176,
    "indexSizes" : {
        "_id_" : 8176
    },
    "ok" : 1
}

使用例:

// from("direct:getColStats").to("mongodb:myDb?database=flights&collection=tickets&operation=getColStats");
Object result = template.requestBody("direct:getColStats", "irrelevantBody");
assertTrue("Result is not of type DBObject", result instanceof DBObject);

この操作は、シェルに表示されるものと同様のデータ構造を、OUT メッセージ本文の DBObject の形式で返します。

227.5.5.4. command

Camel 2.15 以降で利用可能

データベースで本体をコマンドとして実行します。ホスト情報、レプリケーション、またはシャーディングステータスを取得するなどの管理操作に役立ちます。

コレクションパラメーターは、この操作では使用されません。

// route: from("command").to("mongodb:myDb?database=science&operation=command");
DBObject commandBody = new BasicDBObject("hostInfo", "1");
Object result = template.requestBody("direct:command", commandBody);

227.5.6. 動的操作

エクスチェンジは、MongoDbConstants.OPERATION_HEADER 定数で定義された CamelMongoDbOperation ヘッダーを設定することにより、エンドポイントの固定操作をオーバーライドできます。
サポートされる値は、MongoDbOperation 列挙によって決定され、エンドポイント URI の operation パラメーターで受け入れられる値と一致します。

以下に例を示します。

// from("direct:insert").to("mongodb:myDb?database=flights&collection=tickets&operation=insert");
Object result = template.requestBodyAndHeader("direct:insert", "irrelevantBody", MongoDbConstants.OPERATION_HEADER, "count");
assertTrue("Result is not of type Long", result instanceof Long);