Menu Docs

Página inicial do DocsServiços Atlas App

Fazer alterações significativas no esquema

Nesta página

  • Visão geral
  • Collections de parceiros
  • Procedimento
  • Inicialize sua collection de parceiros com uma pipeline de agregação
  • Configurar triggers de banco de dados para suas coleções de parceiros
  • Adicionar funções de trigger
  • Modo de desenvolvimento e alterações significativas

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 uma collection de parceiros, 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.

No procedimento abaixo, a collection inicial usa o esquema JSON abaixo para uma collection do Task. Observe que o esquema do Task contém um campo _id do tipo objectId:

Esquema de tarefa
{
"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:

Esquema de tarefa
{
"title": "Task",
"bsonType": "object",
"required": [
"_id",
"name"
],
"properties": {
"_id": {
"bsonType": "string"
},
"_partition": {
"bsonType": "string"
},
"name": {
"bsonType": "string"
}
}
}
1

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:

  1. Combine todos os documentos na collection inicial passando um filtro vazio para o operador $match.

  2. 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 tipo string com o operador $toString.

  3. 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:

UI do Atlas para o construtor de aggregations

O exemplo a seguir mostra o aggregation pipeline completo como seria se você usasse mongosh para fazer a conversão:

Corresponder todos os documentos da collection inicial e enviá-los para a collection de parceiros
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
]);
2

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.

3

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 aggregation 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 coleção TaskV2 . Finalmente, os dados transformados são escritos na collection TaskV2 usando o operador $merge:

função copyTaskObjectToTaskV2
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:

função CopyTaskV2ObjectToTask
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);
};

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.

← Atualize seu modelo de dados