Fazer alterações significativas no esquema
Nesta página
Visão geral
Se for necessário fazer alterações em um esquema de objeto usado no Atlas Device Sync, você poderá fazer elas não significativas sem nenhum trabalho adicional. No entanto, alterações significativas exigem etapas adicionais. Uma alteração significativa ou destrutiva inclui renomear um campo existente ou alterar o tipo de dados de um campo.
Para mais informações, consulte Atualizar seu Modelo de Dados.
Se precisar fazer uma alteração significativa no esquema, você terá duas opções:
Encerre a sincronização no backend e, em seguida, reative-a desde o início.
Crie umacollection de parceiro , copie os dados antigos para essa nova collection e configure gatilhos para garantir a consistência dos dados.
O restante deste guia ensina a criar uma collection de parceiros.
Aviso
Restaurar a sincronização após encerrar a sincronização
Quando você encerra e reativa o Atlas Device Sync, os clientes não podem mais sincronizar. Seu cliente deve implementar um manipulador de redefinição de cliente para restaurar a sincronização. Este manipulador pode descartar ou tentar recuperar alterações não sincronizadas.
Collections de parceiros
No procedimento abaixo, a collection inicial usa o JSON schema abaixo para uma collection do Task
. Observe que o esquema do Task
contém um campo _id
do tipo objectId
:
{ "title": "Task", "bsonType": "object", "required": [ "_id", "name" ], "properties": { "_id": { "bsonType": "objectId" }, "_partition": { "bsonType": "string" }, "name": { "bsonType": "string" } } }
O novo esquema é o mesmo, exceto pelo fato de que queremos que o campo _id
seja uma string:
{ "title": "Task", "bsonType": "object", "required": [ "_id", "name" ], "properties": { "_id": { "bsonType": "string" }, "_partition": { "bsonType": "string" }, "name": { "bsonType": "string" } } }
Procedimento
Inicialize sua collection de parceiros com uma pipeline de agregação
Como as alterações de quebra não podem ser realizadas diretamente em um esquema de objeto sincronizado, você deve criar uma coleção de parceiros com um esquema contendo as alterações necessárias. Você deve garantir que a coleta de parceiro tenha os mesmos dados que a coleta original para que clientes mais novos possam sincronizar com clientes mais antigos.
A abordagem recomendada para copiar os dados da sua coleção original para a nova coleção de parceiros é usar a Estrutura de agregação.
Você pode criar e executar uma pipeline de agregação a partir do mongo shell, usando o /aggregation-pipeline-builder/ ou com o /data-explorer/cloud-agg-pipeline/.
O pipeline terá os seguintes estágios:
Combine todos os documentos na coleção inicial passando um filtro vazio para o operador $match.
Modifique os campos da collection inicial usando um operador de pipeline de agregação. No exemplo abaixo, os dados são transformados utilizando o operador $addFields. O campo
_id
é transformado em um tipostring
com o operador $toString.Grave os dados transformados na collection de parceiros usando o operador $out e especificando o nome da collection de parceiros. Neste exemplo, escrevemos os dados em uma nova collection chamada
TaskV2
.
Aqui, a mesma pipeline representado nas UIs do Atlas e Compass. Observe que ambas as ferramentas fornecem uma visualização das alterações; neste caso, a conversão do campo _id
de um ObjectId para uma string:
O exemplo a seguir mostra o pipeline de agregação completo como seria se você usasse mongosh para fazer a conversão:
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 ]);
Configurar triggers de banco de dados para suas coleções de parceiros
Depois que sua collection de parceiros estiver configurada, você poderá usá-la para ler os dados existentes. No entanto, qualquer nova escrita nos dados de qualquer collection não estará na outra collection. Isso faz com que os clientes antigos fiquem fora de sincronia com os novos clientes.
Para garantir que os dados sejam refletidos em ambas as collections, configure um gatilho de banco de dados (trigger) em cada collection. Quando os dados são gravados em uma collection, a função do trigger executa a gravação na collection parceira.
Siga as etapas na documentação do gatilho de banco de dados (trigger) para criar um trigger que irá copiar dados da collection Task
para a collection TaskV2
para todos os tipos de operações. Repita as etapas para criar um segundo trigger que irá copiar dados da collection TaskV2
para a collection Task
.
Adicionar funções de trigger
Os gatilhos exigem funções de suporte que são executadas quando o gatilho é disparado. Nesse caso, precisamos criar duas funções: uma função de migração para a frente e uma função de migração reversa.
O gatilho de migração direta escuta inserções, atualizações e exclusões na collection Tarefa, modifica-as para refletir o esquema da collection TaskV2 e as aplica à collection TaskV2.
Para ouvir as alterações na collection TaskV2 e aplicá-las à collection Task, grave uma função de migração reversa para o trigger da collection TaskV2. A migração reversa segue a mesma ideia da etapa anterior.
Na função de migração direta, verificamos qual operação acionou a função: se o tipo de operação for Delete
(significando que um documento foi excluído na collection de tarefas), o documento também será excluído na collection TaskV2 . Se o tipo de operação for um evento Write
(inserido ou modificado), um agregação pipeline será criado. No pipeline, o documento inserido ou modificado na collection Task é extraído usando o operador $match. O documento extraído é então transformado para aderir ao esquema da collection TaskV2
. Finalmente, os dados transformados são escritos na collection TaskV2
usando o operador $merge:
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); };
A função de migração reversa passa por etapas semelhantes ao exemplo na etapa anterior. Se um documento foi excluído em uma collection, ele também será excluído na outra collection. Se o tipo de operação for um evento de gravação, o documento alterado de TaskV2
será extraído, transformado para corresponder ao esquema da collection de tarefas e gravado na collection 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); };
Modo de desenvolvimento e alterações significativas
Aplica-se a apps do App Services criadas após 13 de setembro de 2023.
App Services Apps no modo de desenvolvimento que foram criados depois de 13 de setembro de 2023 podem fazer alterações significativas no código do cliente para esquemas de objetos sincronizados.
Consulte o Modo de desenvolvimento para obter detalhes sobre como fazer alterações significativas no Modo de desenvolvimento.
O modo de desenvolvimento não é adequado para uso em produção. Se você usar o modo de desenvolvimento, certifique-se de desativá-lo antes de mover sua aplicação para a produção.