スキーマの重大な変更の実施
項目一覧
Overview
Atlas Device Sync で使用されるオブジェクト スキーマに変更を加える必要がある場合は、追加作業なしで非重大度を実現できます。 ただし、重大な変更には追加の手順が必要です。 重大な変更または破壊的な変更には、既存のフィールドの名前の変更や、フィールドのデータ型の変更が含まれます。
詳しくは、「データモデルを更新する 」を参照してください。
スキーマの重大な変更を行う必要がある場合は、次の 2 つの選択肢があります。
パートナー コレクションを作成し 、古いデータをこの新しいコレクションにコピーし、trigger を設定してデータの一貫性を確保します。
このガイドの残りの部分では、パートナー コレクションの作成について説明します。
警告
同期終了後の同期の復元
Atlas Device Sync を終了して再度有効にすると、クライアントは同期できなくなります。 同期を復元するには、クライアントがクライアント リセット ハンドラーを実装する必要があります。 このハンドラーは、同期されていない変更を破棄したり、回復を試行したりできます。
パートナー コレクション
次の手順では、初期コレクションは Task
コレクションに対して以下の JSON schema を使用します。 Task
のスキーマには、 objectId
型の_id
フィールドが含まれていることに注意してください。
{ "title": "Task", "bsonType": "object", "required": [ "_id", "name" ], "properties": { "_id": { "bsonType": "objectId" }, "_partition": { "bsonType": "string" }, "name": { "bsonType": "string" } } }
新しいスキーマは同じですが、 _id
フィールドが string である必要があります。
{ "title": "Task", "bsonType": "object", "required": [ "_id", "name" ], "properties": { "_id": { "bsonType": "string" }, "_partition": { "bsonType": "string" }, "name": { "bsonType": "string" } } }
手順
集計パイプラインを使用してパートナー コレクションを初期化
同期されたオブジェクト スキーマでは重大な変更を直接実行できないため、必要な変更を含むスキーマでパートナー コレクションを作成する必要があります。 新しいクライアントが古いクライアントと同期できるように、パートナー コレクションが元の コレクションと同じデータを持つことを確認する必要があります。
元のコレクションから新しいパートナー コレクションにデータをコピーする際の推奨される方法は、集計フレームワーク を使用することです。
/aggregation- pipeline-Builder/ を使用するか、 /data-explorer/cloud-agg-pipeline/ を使用して、 mongo shell から集計パイプラインを作成して実行することができます。
パイプラインには、次のステージが含まれます。
集計パイプライン演算子を使用して、初期コレクションのフィールドを変更します。 次の例では、データは$addFields 演算子を使用して変換されます。
_id
フィールドは$toString 演算子を使用してstring
型に変換されます。$out 演算子を使用し、パートナーコレクション名を指定して、変換されたデータをパートナーコレクションに書き込みます。 この例では、
TaskV2
という名前の新しいコレクションにデータを書込みました。
ここでは、Atlas および Compass UI で表されるのと同じパイプラインが示されます。 これらのツールはどちらも変更のプレビューを提供していることに注意してください。この場合、 _id
フィールドを ObjectId から string に変換します。
次の例は、 mongoshを使用して変換を実行した場合に生じる完全な集計パイプラインを示しています。
use "<database-name>" // switch the current db to the db that the Task collection is stored in collection = db.Task; collection.aggregate([ { $match: {} }, // match all documents in the Task collection { $addFields: { // transform the data _id: { $toString: "$_id" }, // change the _id field of the data to a string type }, }, { $out: "TaskV2" }, // output the data to a partner collection, TaskV2 ]);
パートナーコレクションのデータベーストリガーを設定する
パートナー コレクションが設定されると、それを使用して既存のデータを読み取ることができます。 ただし、どちらのコレクションのデータにも新たに書込み (write) は、もう 1 つのコレクションには含まれません。 これにより、古いクライアントは新しいクライアントと同期されなくなります。
両方のコレクションにデータが反映されるようにするには、各コレクションにデータベースtriggerを設定します。 データが 1 つのコレクションに書き込まれると、trigger の関数はパートナー コレクションへの書込みを実行します。
データベースtriggerのドキュメントの手順に従って、すべての操作タイプに対して Task
コレクションから TaskV2
コレクションにデータをコピーするtriggerを作成します。 これらの手順を繰り返して、TaskV2
コレクションから Task
コレクションにデータをコピーする 2 つ目のtriggerを作成します。
trigger 関数を追加する
trigger には、trigger が起動したときに実行されるバッキング 関数が必要です。 この場合は、順方向移行関数と逆移行関数の 2 つの関数を作成する必要があります。
順方向移行triggerは、Task コレクション内の挿入、アップデート、削除をリッスンし、TaskV2 コレクションのスキーマを反映するようにそれらを変更し、TaskV2 コレクションに適用します。
TaskV2 コレクションへの変更をリッスンし、それらを Task コレクションに適用するには、TaskV2 コレクションの trigger の逆移行関数を記述します。 逆の移行は、前の手順と同じ概念に従います。
順方向移行関数では、どの操作が関数をトリガーしたかを確認します。操作タイプがDelete
(Task コレクションでドキュメントが削除された場合)の場合、そのドキュメントは TaskV 2コレクションでも削除されます。 操作タイプがWrite
(挿入または変更)イベントの場合、集計パイプラインが作成されます。 パイプラインでは、タスク コレクションに挿入または変更されたドキュメントは、 $match 演算子を使用して抽出されます。 抽出されたドキュメントは、次に、 TaskV2
コレクションのスキーマに準拠するように変換されます。 最後に、変換されたデータは、 $merge 演算子を使用してTaskV2
コレクションに書き込まれます。
exports = function (changeEvent) { const db = context.services.get("mongodb-atlas").db("ExampleDB"); const collection = db.collection("Task"); // If the event type is "invalidate", the next const throws an error. // Return early to avoid this. if (!changeEvent.documentKey) { return; } // The changed document's _id as an integer: const changedDocId = changeEvent.documentKey._id; // If a document in the Task collection has been deleted, // delete the equivalent object in the TaskV2 collection: if (changeEvent.operationType === "delete") { const tasksV2Collection = db.collection("TaskV2"); // Convert the deleted document's _id to a string value // to match TaskV2's schema: const deletedDocumentID = changedDocId.toString(); return tasksV2Collection.deleteOne({ _id: deletedDocumentID }) } // A document in the Task collection has been created, // modified, or replaced, so create a pipeline to handle the change: const pipeline = [ // Find the changed document data in the Task collection: { $match: { _id: changeEvent.documentKey._id } }, { // Transform the document by changing the _id field to a string: $addFields: { _id: { $toString: "$_id" }, }, }, // Insert the document into TaskV2, using the $merge operator // to avoid overwriting the existing data in TaskV2: { $merge: "TaskV2" }] return collection.aggregate(pipeline); };
この逆移行関数は、前のステップの例と同様の手順を通過します。 1 つのコレクションでドキュメントが削除された場合、そのドキュメントは他のコレクションでも削除されます。 操作タイプが書込みイベントの場合、 TaskV2
から変更されたドキュメントが抽出され、Task コレクションのスキーマと一致するように変換され、 Task
コレクションに書込まれます。
exports = function (changeEvent) { const db = context.services.get("mongodb-atlas").db("ExampleDB"); const collection = db.collection("TaskV2"); // If the event type is "invalidate", the next const throws an error. // Return early to avoid this. if (!changeEvent.documentKey) { return; } // The changed document's _id as a string: const changedDocId = changeEvent.documentKey._id; // If a document in the TaskV2 collection has been deleted, // delete the equivalent object in the Task collection if (changeEvent.operationType === "delete") { const taskCollection = db.collection("Task"); // Convert the deleted document's _id to an integer value // to match Task's schema: const deletedDocumentID = parseInt(changedDocId); return taskCollection.deleteOne({ _id: deletedDocumentID }) } // A document in the Task collection has been created, // modified, or replaced, so create a pipeline to handle the change: const pipeline = [ // Find the changed document data in the Task collection { $match: { _id: changedDocId } }, { // Transform the document by changing the _id field $addFields: { _id: { $toInt: "$_id" }, }, }, { $merge: "Task" } ] return collection.aggregate(pipeline); };
開発モードと重大な変更
2023 年 9 月 13 日以降に作成された App Services アプリに適用されます。
2023 年 9 月 13 日以降に作成された 開発モード の App Services アプリは、クライアント コードから同期されたオブジェクト スキーマに重大な変更を加える可能性があります。
開発モードで重大な変更を加えるための詳細については、 「 開発モード 」を参照してください。
開発モードは本番環境での使用には適していません。 開発モードを使用する場合は、アプリを本番環境に移行する前に必ずこのモードを無効にしてください。