Prólogo
Este artigo o orienta em uma migração única do MongoDB para o Couchbase. Você aprenderá a exportar da estrutura de dados do MongoDB, importar para o Couchbase e fazer algumas transformações básicas nesses documentos.
Todo o código deste blog está disponível no seguinte repositório Git: mongodb-to-couchbase
Pré-requisitos
Este artigo usa o conjunto de dados de amostra mflix que foi carregado em um cluster do MongoDB. Estou usando o MongoDB Atlas, mas as informações deste artigo também se aplicam a instalações do MongoDB que não sejam do Atlas. Se você precisar carregar o conjunto de dados de amostra para o MongoDB, consulte o artigo instruções aqui.
MongoDB Compass é usado para exportar o conjunto de dados e este artigo pressupõe que ele já esteja configurado para se conectar ao cluster do MongoDB onde reside o conjunto de dados de amostra mflix.
Você também precisará de um cluster do Couchbase Server Enterprise Edition (EE) 6.5 com os serviços Data, Index, Query e Eventing ativados (OBSERVAÇÃO: Index e Query serão usados em um artigo futuro). Estou usando uma instalação local de nó único do Couchbase Server EE, mas as informações neste artigo se aplicam a qualquer cluster do Couchbase Server EE.
Se você não tiver um cluster existente do Couchbase Server EE, os links a seguir o ajudarão a começar a trabalhar rapidamente:
- Faça o download do Couchbase Sever EE 6.5
- Instalar o Couchbase Server EE
- Provisione um cluster de nó único (OBSERVAÇÃO: use os valores padrão para a configuração do cluster).
JSON, BSON e JSON estendido
O MongoDB e o Couchbase são bancos de dados de documentos e ambos armazenam documentos JSON. No entanto, o MongoDB representa documentos JSON em um formato codificado em binário chamado BSON. O JSON só pode representar um subconjunto dos tipos suportados pelo BSON. Para preservar as informações de tipo, o MongoDB usa o Extended JSON, que inclui extensões para o formato JSON. Consulte a seção Especificação JSON estendida do MongoDB para obter detalhes completos sobre os diferentes tipos e convenções do Extended JSON.
Aqui estão alguns exemplos de como o MongoDB representa diferentes tipos de informações:
- ObjectId: “_id”:{“$oid”:”573a1390f29313caabcd4135″}
- Inteiro: "runtime":{"$numberInt": "1″}
- Data: “released”:{“$date”:{“$numberLong”:”-2418768000000″}}
- Duplo: "rating":{"$numberDouble": "6.2″}
Embora o Couchbase possa armazenar essas informações, é mais fácil trabalhar com documentos que não usam o formato JSON estendido. Usando os exemplos acima, os valores teriam a seguinte aparência:
- ObjectId: “_id”:”573a1390f29313caabcd4135″
- Inteiro: "runtime":1
- Data: “released”:-2418768000000
- Duplo: "rating":6.2
Exportar dados do MongoDB
Use o MongoDB Compass para exportar o filmes e comentários coleções do sample_mflix banco de dados. No Compass, expanda a seção sample_mflix item do banco de dados e, em seguida, selecione comentários.

Escolha o Coleção -> Coleção de exportação item de menu. Selecione Exportar coleção completa e clique em SELECIONAR CAMPOS.

Selecione todos os campos e clique em SELECIONAR SAÍDA.

Selecione JSON tipo de arquivo de exportação, especifique o arquivo de saída e clique em EXPORTAÇÃO.

Faça o mesmo com o filmes coleção.
Importar dados para o Couchbase
Em seguida, importe os dados da coleção do MongoDB para o Couchbase. Conforme mencionado acima, os dados exportados estão no formato JSON estendido, portanto o Couchbase Serviço de eventos é usado para fazer algumas pequenas transformações nos dados em tempo real à medida que os documentos são importados para o Couchbase.
Em um nível elevado, o fluxo é o seguinte:
- Use o Utilitário cbimport para importar os documentos JSON para o de entrada balde.
- Como os documentos são gravados no de entrada balde, uma função Eventing transformará os documentos.
- Se a transformação for bem-sucedida, o documento transformado será gravado no arquivo sample_mflix balde.
- Se houver algum erro, o documento original é gravado no erro balde. Um atributo de erro no documento conterá a mensagem de erro.
Criar baldes
Crie os três buckets mencionados acima. Consulte a seção documentação sobre a criação de um bucket para obter detalhes completos sobre as diferentes configurações e considerações sobre a definição dos valores.
O de entrada O bucket armazenará temporariamente os documentos à medida que eles forem importados para o Couchbase. Esse é um balde efêmero já que não precisamos de nenhum armazenamento persistente para esses documentos. Uma função Eventing os transformará e os gravará no sample_mflix ou no bucket de erros.
Como os documentos não precisam permanecer no bucket depois de serem transformados, o bucket é configurado com um Tempo de vida (TTL) de 900 segundos (15 minutos). Os documentos são excluídos automaticamente pelo Couchbase quando o TTL expirações.
Para criar o de entrada clique em Baldes e depois ADICIONAR BALDE.

Configurar o de entrada como segue e clique em Adicionar balde.
- Nome: entrada
- Cota de memória: 256 MB (OBSERVAÇÃO: os compartimentos efêmeros não persistem no disco, portanto, é necessário garantir que haja memória suficiente alocada ao compartimento para acomodar todo o conjunto de dados que está sendo importado. O tamanho total das coleções de comentários e filmes usadas neste exemplo é de cerca de 50 MB, portanto, 256 MB é mais do que suficiente para acomodar esse conjunto de dados).
- Tipo de caçamba: Efêmero
- Configurações avançadas do Bucket -> Tempo máximo de vida do balde(OBSERVAÇÃO: os documentos são transformados em tempo real à medida que são gravados no Couchbase, portanto, esse valor pode ser definido como relativamente baixo. No caso, são usados 15 minutos (900 segundos). Se o valor for definido como muito baixo, o documento poderá expirar antes de ser processado).

O sample_mflix é usado para armazenar o documento transformado. Esse é um Balde do Couchbase já que precisamos de armazenamento persistente para esses documentos. Configure-o da seguinte forma:
- Nome: sample_mflix
- Cota de memória256 MB (OBSERVAÇÃO: os buckets do Couchbase persistem todos os documentos no disco, portanto, a cota de memória determinará quantos documentos podem ser armazenados no camada de cache integrada a qualquer momento. O tamanho total das coleções de comentários e filmes usadas neste exemplo é de cerca de 50 MB, portanto, 256 MB é mais do que suficiente para acomodar esse conjunto de dados).
- Tipo de caçamba: Couchbase

O erro é usado para armazenar todos os documentos que não puderam ser transformados. Configure-o da seguinte forma:
- Nome: erro
- Cota de memória: 256 MB
- Tipo de caçamba: Couchbase

Transformação de dados com eventos
Eventos é usado para transformar os dados em tempo real à medida que eles são importados para o Couchbase. Há algumas coisas a serem configuradas para usar esse recurso.
Primeiro, crie um metadados balde que é usado pelo Eventing para armazenar dados do sistema. Configure-o da seguinte forma:
- Nome: metadados
- Cota de memória: 256 MB
- Tipo de caçamba: Couchbase

O Baldes agora lista os 4 compartimentos que você criou: error, incoming, metadata e sample_mflix:

Clique em Eventos e, em seguida, clique em ADICIONAR FUNÇÃO para configurar a função que é usada para transformar os dados em tempo real à medida que são importados para o Couchbase.

Configure a função da seguinte forma:
- Balde de origem: incoming (Esse bucket armazena temporariamente os documentos à medida que eles são importados para o Couchbase)
- Balde de metadadosMetadados: (Esse compartimento é usado para armazenar dados do sistema)
- Nome da função: transformação
- Descrição: Transformar a exportação do MongoDB
- Vinculações (Clique no botão + para adicionar um segundo vínculo)
- tipo de ligação: alias do balde
- nome do aliastarget (alias usado na função para se referir ao bucket)
- balde: sample_mflix (nome do bucket no cluster)
- acesso: leitura e gravação
-
- tipo de ligação: alias do balde
- nome do aliasErro (alias usado na função para se referir ao bucket)
- balde: erro (nome do bucket no cluster)
- acesso: leitura e gravação

Clique em Próximo: Adicionar código para adicionar o código JavaScript para o transformar função.
Na tela da função de transformação, substitua o código padrão pelo código abaixo.
A função inclui instruções log() para registrar o documento original, o documento transformado e quaisquer erros. Fique à vontade para alterá-las conforme necessário. O arquivo de registro de entradas do Eventing é eventing.log e pode ser encontrado no registro do aplicativo @eventing. Veja este link para obter mais informações sobre o nome do arquivo de registro e como visualizá-lo.
Você pode facilmente ampliar a capacidade dessa função para realizar outras transformações adicionando o código necessário na função transformValues(). Se precisar fazer alguma alteração na função, você precisará pausar ou cancelar a implantação, editar o JavaScript e, em seguida, retomar ou implantar novamente.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
function OnUpdate(doc, meta) { log("original document: ", doc); try { // transform document var newDoc = transformValues(null, "", doc); // add a type attribute based on the document ID (available in meta.id) newDoc["type"] = getTypeFromId(meta.id); // generate a document ID for the transformed document based on the type and the _id attribute value var id = generateId(newDoc); log("transformed document (id = " + id + "): ", newDoc); // write transformed document to target bucket with generated ID target[id] = newDoc; } catch (e) { log("error transforming document " + meta.id + ". See error bucket for more details."); // if there are any errors, store error message in the error attribute doc["error"] = e; // write untransformed document to error bucket with original ID error[meta.id] = doc; } } function OnDelete(meta) { } // This is a recursive function that will iterate over all properties in the document (including arrays & sub-objects) // It will transform Extended JSON to standard JSON. function transformValues(parentObj, parentProperty, obj) { var propertyType = ""; // for every property in the object for (var property in obj) { if (obj.hasOwnProperty(property) && obj[property] != null) { switch (property) { case "$oid": // convert parentObj.parentProperty = {"$oid":"3487634876"} // to parentObj.parentProperty = "3487634876" parentObj[parentProperty] = obj[property]; break; case "$date": if (obj["$date"]["$numberLong"] != null) { // convert parentObj.parentProperty = {"$date":{"$numberLong":"-2418768000000"}} // to parentObj.parentProperty = -2418768000000 parentObj[parentProperty] = Number(obj["$date"]["$numberLong"]); break; } // convert parentObj.parentProperty = {"$date":"1983-04-27T20:39:15Z"}} // to parentObj.parentProperty = "1983-04-27T20:39:15Z" parentObj[parentProperty] = obj["$date"]; break; case "$numberInt": case "$numberDecimal": case "$numberLong": case "$numberDouble": // convert parentObj.parentProperty = {"$numberInt":"1"} // to parentObj.parentProperty = 1 parentObj[parentProperty] = Number(obj[property]); break; // !!! This function can be extended by adding additional case statements here !!! default: // otherwise, check the property type propertyType = determineType(obj[property]); switch (propertyType) { case "Object": // if the property is an object, recursively transform the object transformValues(obj, property, obj[property]); break; case "Array": // if the property is an array, transform every element in the array transformArray(obj[property]); break; default: // otherwise, do nothing break; } } } } return obj; } // Determine the type of the specified object function determineType(obj) { return obj == null ? "null" : obj.constructor.name; } // Transform every element in the specified array function transformArray(obj) { for (var i = 0; i < obj.length; i++) { transformValues(obj, i, obj[i]); } } // Get document type from specified id. // This function expects that documents will be imported with IDs in the following format: // example: <document type>:12 function getTypeFromId(id) { return id.split(":")[0]; } // Generate a document ID for the specified document. // The new ID will be based on the value of the type attribute and the value of the _id attribute: // <type>:<_id> function generateId(document) { var documentId = document["_id"]; if (determineType(documentId) != "String") { throw "'_id' value must be a String: _id = '" + documentId + "'"; } return document["type"] + ":" + documentId; } |
Clique em Salvar para salvar o código e clique em < voltar para Eventing para voltar ao Eventos seção do console.

Você verá o novo transformar mas ele precisa ser implantado. Clique no ícone transformar e, em seguida, clique em Implementar.

Confirme a implementação da função com a configuração padrão clicando em Função de implantação.

Depois que a função for implementada, o status será implantado.

Agora tudo está pronto para importar os dados de exportação do MongoDB para o Couchbase e transformá-los em tempo real.
Importar documentos com o cbimport
Use o Utilitário cbimport para importar os arquivos de exportação do MongoDB. Antes de importar os dados, é importante entender a sintaxe do comando e o que ele está fazendo.
Aqui está um exemplo de comando cbimport:
|
1 |
$ cbimport json -c <cluster> -u <admin username> -p <admin password> -b <bucket> -d <import file> -f <file format> -g <key generator> |
Para importar o MongoDB comentários execute o comando abaixo. Observe que o local do utilitário cbimport varia de acordo com o sistema operacional e está documentado aqui: Referência da CLI.
|
1 |
$ <path_to_cbimport>/cbimport json -c <cluster> -u <admin username> -p <admin password> -b incoming -d file://<path to comments.json>/comments.json -f list -g comment:#MONO_INCR# |
O comando se conectará ao cluster especificado (ou seja, -c couchbase://127.0.0.1) usando as credenciais de administrador fornecidas (ou seja, -u Administrator -p password).
O comando importará dados JSON de comments.json. Verifique o formato do arquivo comments.json exportado e especifique o opção de formato de conjunto de dados com base no formato do arquivo de exportação. Meu arquivo de exportação segue o formato formato de lista que contém uma única lista JSON em que cada elemento da lista representa um documento separado (-f list).
Os documentos são gravados no bucket de entrada (-b incoming) usando uma chave gerada usando o formato especificado (-g comment:#MONO_INCR#). Nesse comando, o formato especifica que cada chave de documento começará com "comment:". A chave Função MONO_INCR aumenta em 1 cada vez que é chamado, de modo que as chaves resultantes são comment:1, comment:2, etc.
Após a conclusão, você verá o seguinte resultado:
|
1 2 |
Json `file://comments.json` imported to `https://127.0.0.1:8091` successfully. Documents imported: 50304 Documents failed: 0 |
Ir para o Baldes e confirme que o sample_mflix O balde contém 50.304 documentos.

Para importar o MongoDB filmes execute o comando abaixo.
|
1 |
$ <path_to_cbimport>/cbimport json -c <cluster> -u <admin username> -p <admin password> -b incoming -d file://<path to movies.json>/movies.json -f list -g movie:#MONO_INCR# |
Após a conclusão, você verá o seguinte resultado:
|
1 2 |
Json `file://movies.json` imported to `https://127.0.0.1:8091` successfully. Documents imported: 23539 Documents failed: 0 |
Ir para o Baldes e confirme que o sample_mflix O balde contém 73.843 documentos.

Agora, verifique dois dos documentos transformados. Vá para o documento Documentos e certifique-se de que a seção Balde é definido como sample_mflix. Clique em id comment:5a9427648b0beebeb69579cc (o primeiro documento da lista):

Observe o conteúdo:
|
1 2 3 4 5 6 7 8 9 |
{ "_id": "5a9427648b0beebeb69579cc", "name": "Andrea Le", "email": "andrea_le@fakegmail.com", "movie_id": "573a1390f29313caabcd418c", "text": "Rem officiis eaque repellendus amet eos doloribus. Porro dolor voluptatum voluptates neque culpa molestias. Voluptate unde nulla temporibus ullam.", "date": "2012-03-26T23:20:16Z", "type": "comment" } |
Comparando-o com os dados exportados (procure por 5a9427648b0beebeb69579cc em comments.json):
|
1 2 3 4 5 6 7 8 |
{ "_id":{"$oid":"5a9427648b0beebeb69579cc"}, "name":"Andrea Le", "email":"andrea_le@fakegmail.com", "movie_id":{"$oid":"573a1390f29313caabcd418c"}, "text":"Rem officiis eaque repellendus amet eos doloribus. Porro dolor voluptatum voluptates neque culpa molestias. Voluptate unde nulla temporibus ullam.", "date": {"$date": "2012-03-26T23:20:16Z"} } |
A função de transformação alterou os valores Extended JSON _id, movie_id e date. Observe que um atributo de tipo foi adicionado com base no prefixo da chave do documento (lembre-se de que especificamos comentário como o prefixo da chave ao importar os dados).
Feche o editor de documentos quando terminar de revisar o conteúdo do documento.
No ID do documento campo enter movie:573a1390f29313caabcd4135, clique em Recuperar documentose clique em id movie:573a1390f29313caabcd4135.

Observe o conteúdo:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
{ "_id": "573a1390f29313caabcd4135", "plot": "Three men hammer on an anvil …", "genres": [ "Short" ], "runtime": 1, "cast": [ "Charles Kayser", "John Ott" ], "num_mflix_comments": 1, "title": "Blacksmith Scene", "fullplot": "A stationary camera looks at a large anvil …", "countries": [ "USA" ], "released": -2418768000000, "directors": [ "William K.L. Dickson" ], "rated": "UNRATED", "awards": { "wins": 1, "nominations": 0, "text": "1 win." }, "lastupdated": "2015-08-26 00:03:50.133000000", "year": 1893, "imdb": { "rating": 6.2, "votes": 1189, "id": 5 }, "type": "movie", "tomatoes": { "viewer": { "rating": 3, "numReviews": 184, "meter": 32 }, "lastUpdated": "2015-06-28T18:34:09Z" } } |
Comparando-o com os dados exportados (procure por 573a1390f29313caabcd4135 em movies.json):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
{ "_id": {"$oid": "573a1390f29313caabcd4135"}, "plot": "Three men hammer on an …", "genres": [ "Short" ], "runtime": 1, "cast": [ "Charles Kayser", "John Ott" ], "num_mflix_comments": 1, "title": "Blacksmith Scene", "fullplot": "A stationary camera looks at a large anvil …", "countries": [ "USA" ], "released": {"$date": {"$numberLong": "-2418768000000"}}, "directors":[ "William K.L. Dickson" ], "rated": "UNRATED", "awards": { "wins": 1, "nominations": 0, "text": "1 win." }, "lastupdated": "2015-08-26 00:03:50.133000000", "year": 1893, "imdb": { "rating": 6.2, "votes": 1189, "id": 5 }, "type": "movie", "tomatoes": { "viewer": { "rating": 3, "numReviews" 184, "meter": 32 }, "lastUpdated": {"$date": "2015-06-28T18:34:09Z"} } } |
A função de transformação alterou os valores Extended JSON _id, released e tomatoes.lastUpdated. Observe que um atributo de tipo não foi adicionado nesse caso. O documento exportado já continha um atributo de tipo, portanto, a função de transformação não adicionou um, mas definiu o valor com base no prefixo da chave (lembre-se de que especificamos movie como o prefixo da chave ao importar os dados).
Feche o editor de documentos quando terminar de revisar o conteúdo do documento.
O que vem a seguir
Se você não planeja importar mais dados de exportação do MongoDB, pode cancelar a implantação da função de transformação e remover os buckets de entrada e de erro.
-
- Um artigo futuro abordará como atualizar o código do cliente existente para usar o SDK do Couchbase.
- Aproveite nosso treinamento on-line gratuito, disponível em https://learn.couchbase.com para saber mais sobre o Couchbase.
- Confira os vários IDEs para desenvolvedores do Couchbase - JetBrains, VSCodepara os quais temos plug-ins.
Para obter informações detalhadas sobre os diferentes modelos de documentos entre o Couchbase e o MongoDB, a modelagem de dados e o esquema do MongoDB e outras formas de comparar o MongoDB com o Couchbase, consulte este documento: Couchbase: Melhor que o MongoDB em todos os sentidos.
Saiba por que outras empresas escolhem o Couchbase em vez do MongoDB: