{"id":2083,"date":"2015-09-30T18:22:47","date_gmt":"2015-09-30T18:22:46","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=2083"},"modified":"2025-06-13T23:54:07","modified_gmt":"2025-06-14T06:54:07","slug":"sync-with-couchbase-using-only-angularjs-and-pouchdb","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/pt\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/","title":{"rendered":"Sincroniza\u00e7\u00e3o com o Couchbase usando apenas AngularJS e PouchDB"},"content":{"rendered":"<p>H\u00e1 muitas maneiras de usar o Couchbase em seu aplicativo da Web ou m\u00f3vel por meio de um dos v\u00e1rios SDKs de linguagem. No entanto, e se voc\u00ea n\u00e3o estiver usando uma linguagem de back-end como PHP ou uma linguagem m\u00f3vel como Objective-C? O que acontece se voc\u00ea estiver usando um servi\u00e7o da Web hospedado estaticamente, como o Amazon S3, em que voc\u00ea s\u00f3 tem habilidades de HTML, CSS e JavaScript?<\/p>\n<p>\u00c9 nesse ponto que o PouchDB pode entrar em a\u00e7\u00e3o. <a href=\"https:\/\/pouchdb.com\/\">PouchDB<\/a> \u00e9 uma biblioteca de sincroniza\u00e7\u00e3o e armazenamento projetada para funcionar em um navegador da Web usando JavaScript. N\u00e3o \u00e9 necess\u00e1rio nenhum c\u00f3digo de back-end ou SDKs para usar essa biblioteca com o Couchbase. O PouchDB pode assumir a fun\u00e7\u00e3o de SDK do lado do cliente e replicar os dados de e para o Couchbase Sync Gateway. Mas o PouchDB usa JavaScript b\u00e1sico, ent\u00e3o o que acontece quando seu aplicativo usa AngularJS?<\/p>\n<p>Vamos dar uma olhada em como envolver v\u00e1rias fun\u00e7\u00f5es no PouchDB para torn\u00e1-lo mais amig\u00e1vel ao AngularJS.<\/p>\n<h2>O que ser\u00e1 necess\u00e1rio<\/h2>\n<p>H\u00e1 alguns requisitos para o aplicativo que vamos criar. Veremos como obt\u00ea-los ao longo do caminho, mas aqui est\u00e1 uma amostra para que voc\u00ea saiba no que est\u00e1 se metendo.<\/p>\n<ul>\n<li>Python para executar um servidor HTTP simples ou algo semelhante<\/li>\n<li>Gateway de sincroniza\u00e7\u00e3o do Couchbase<\/li>\n<li>PouchDB 4<\/li>\n<li>AngularJS 1<\/li>\n<li>A biblioteca AngularJS UI-Router vers\u00e3o 0.2<\/li>\n<li>Twitter Bootstrap 3<\/li>\n<\/ul>\n<h2>Estabelecendo a base para nosso projeto<\/h2>\n<p>Antes de entrarmos no c\u00f3digo, vamos situar a estrutura do nosso projeto e colocar todas as bibliotecas e estilos no lugar.<\/p>\n<p>Em algum lugar de seu computador, crie o diret\u00f3rio <strong>PouchDB<\/strong> e adicione os seguintes diret\u00f3rios na raiz:<\/p>\n<ul>\n<li>css<\/li>\n<li>fontes<\/li>\n<li>js<\/li>\n<li>modelos<\/li>\n<\/ul>\n<p>Na raiz do seu projeto, voc\u00ea tamb\u00e9m dever\u00e1 criar um arquivo chamado <strong>index.html<\/strong> e um arquivo chamado <strong>sync-gateway-config.json<\/strong>.<\/p>\n<p>Agora precisamos fazer o download de todas as bibliotecas do nosso projeto. Come\u00e7ando com <a href=\"https:\/\/getbootstrap.com\/\">Twitter Bootstrap<\/a>Fa\u00e7a o download da vers\u00e3o mais recente e coloque todos os <strong>min.css<\/strong> nos arquivos <strong>css<\/strong> de seu projeto, todos os arquivos <strong>min.js<\/strong> nos arquivos <strong>js<\/strong> de seu projeto e todos os arquivos de fonte no diret\u00f3rio <strong>fontes<\/strong> de seu projeto.<\/p>\n<p>Com o Twitter Bootstrap fora do caminho, precisamos fazer o download de <a href=\"https:\/\/angularjs.org\/\">AngularJS<\/a> e o <a href=\"https:\/\/github.com\/angular-ui\/ui-router\">Roteador UI AngularJS<\/a>. Depois de fazer o download dessas bibliotecas, coloque o arquivo <strong>min.js<\/strong> em seu projeto <strong>js<\/strong> diret\u00f3rio.<\/p>\n<p>A \u00faltima biblioteca a ser baixada \u00e9 <a href=\"https:\/\/www.pouchdb.com\">PouchDB<\/a>. Depois de fazer o download do <strong>min.js<\/strong> coloque-o no arquivo <strong>js<\/strong> de seu projeto com todo o restante.<\/p>\n<h3>Obtendo o gateway de sincroniza\u00e7\u00e3o do Couchbase<\/h3>\n<p>Este projeto exigir\u00e1 o Couchbase Sync Gateway para ser bem-sucedido. Se voc\u00ea n\u00e3o estiver familiarizado, o Couchbase Sync Gateway \u00e9 um servi\u00e7o intermedi\u00e1rio que lida com o processamento de dados entre o aplicativo local (seu aplicativo AngularJS) e o Couchbase Server. N\u00e3o usaremos o Couchbase Server neste exemplo, portanto o Sync Gateway atuar\u00e1 como nossa solu\u00e7\u00e3o de armazenamento em mem\u00f3ria na nuvem.<\/p>\n<p>O Couchbase Sync Gateway pode ser encontrado por meio do <a href=\"https:\/\/www.couchbase.com\/blog\/pt\/nosql-databases\/downloads\/\">Se\u00e7\u00e3o de downloads do Couchbase<\/a>.<\/p>\n<h2>Criando nosso projeto<\/h2>\n<p>Agora que todos os arquivos est\u00e3o no lugar, podemos come\u00e7ar a codificar nosso aplicativo.<\/p>\n<h3>Incluindo todos os scripts e estilos<\/h3>\n<p>Vamos come\u00e7ar incluindo todos os estilos e scripts em nosso <strong>index.html<\/strong> arquivo. Abra seu <strong>index.html<\/strong> e inclua o seguinte c\u00f3digo:<\/p>\n<pre><code class=\"language-xhtml\">\r\n<\/code><\/pre>\n<p>Alguns aspectos a serem observados <strong>index.html<\/strong> arquivo. Nomeamos nosso aplicativo AngularJS como <strong>aplicativo de bolsa<\/strong> e estamos usando uma tag que pode parecer estranha:<\/p>\n<p>Essa tag faz parte do AngularJS UI-Router. Este \u00e9 um aplicativo de p\u00e1gina \u00fanica em que cada tela \u00e9 uma parte que \u00e9 carregada nessa tag. Isso far\u00e1 mais sentido em breve.<\/p>\n<h3>Cria\u00e7\u00e3o do arquivo l\u00f3gico do AngularJS<\/h3>\n<p>Dentro da se\u00e7\u00e3o <strong>js<\/strong> crie um arquivo chamado <strong>app.js<\/strong> e inclua o seguinte c\u00f3digo:<\/p>\n<pre><code class=\"language-javascript\">\r\nangular.module(\"pouchapp\", [\"ui.router\"])\r\n\r\n.run(function($pouchDB) {\r\n\r\n})\r\n\r\n.config(function($stateProvider, $urlRouterProvider) {\r\n\r\n})\r\n\r\n.controller(\"MainController\", function($scope, $rootScope, $state, $stateParams, $pouchDB) {\r\n\r\n})\r\n<\/code><\/pre>\n<p>Algumas observa\u00e7\u00f5es sobre esse arquivo em geral e o que vamos fazer. O arquivo <strong>app.js<\/strong> \u00e9 onde toda a l\u00f3gica do nosso aplicativo ser\u00e1 armazenada. Nele, temos um arquivo <strong>.run()<\/strong> que ser\u00e1 executada quando o aplicativo for iniciado, uma fun\u00e7\u00e3o <strong>.config()<\/strong> que configurar\u00e1 todas as telas em nosso aplicativo (UI-Router), e uma fun\u00e7\u00e3o <strong>.controlador()<\/strong> que conter\u00e1 a l\u00f3gica para a funcionalidade do nosso aplicativo espec\u00edfico.<\/p>\n<p>Observe tamb\u00e9m <strong>$pouchDB<\/strong> pois esse \u00e9 um servi\u00e7o AngularJS que projetaremos mais tarde.<\/p>\n<h4>A configura\u00e7\u00e3o do AngularJS<\/h4>\n<p>Como estamos usando o AngularJS UI-Router, precisamos configurar nossas rotas no arquivo <strong>.config()<\/strong> fun\u00e7\u00e3o do <strong>app.js<\/strong> arquivo. O c\u00f3digo seria parecido com o seguinte:<\/p>\n<pre><code class=\"language-javascript\">\r\n$stateProvider\r\n    .state(\"list\", {\r\n        \"url\": \"\/list\",\r\n        \"templateUrl\": \"templates\/list.html\",\r\n        \"controller\": \"MainController\"\r\n    })\r\n    .state(\"item\", {\r\n        \"url\": \"\/item\/:documentId\/:documentRevision\",\r\n        \"templateUrl\": \"templates\/item.html\",\r\n        \"controller\": \"MainController\"\r\n    });\r\n$urlRouterProvider.otherwise(\"list\");\r\n<\/code><\/pre>\n<p>Em resumo, temos duas rotas (telas) aqui. Temos uma tela para mostrar uma lista de algum tipo e uma tela que nos permite adicionar ou atualizar itens da lista. Ambas as rotas usam um controlador AngularJS chamado <strong>Controlador principal<\/strong>mas cada um tem um modelo diferente.<\/p>\n<h5>Os modelos de rota do AngularJS<\/h5>\n<p>Cada tela precisa de seu pr\u00f3prio HTML para ser exibida ao usu\u00e1rio. Na se\u00e7\u00e3o <strong>modelos<\/strong> diret\u00f3rio, crie <strong>list.html<\/strong> e <strong>item.html<\/strong>. Abra o <strong>list.html<\/strong> e adicione o seguinte c\u00f3digo:<\/p>\n<pre><code class=\"language-xhtml\"><button class=\"btn btn-primary\">New Item<\/button><\/code><\/pre>\n<p>&nbsp;<\/p>\n<table class=\"table table-striped\">\n<thead>\n<tr>\n<th>Primeiro nome<\/th>\n<th>Sobrenome<\/th>\n<th>E-mail<\/th>\n<th><\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>{{value.firstname}}<\/td>\n<td>{{value.lastname}}<\/td>\n<td>{{value.email}}<\/td>\n<td><a>editar<\/a> | <a>excluir<\/a><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Muitas dessas coisas podem parecer malucas, mas vou explic\u00e1-las e elas devem fazer mais sentido. Em primeiro lugar, estamos criando uma tabela e fazendo um looping em um objeto, criando uma nova linha de tabela para cada itera\u00e7\u00e3o. Como se trata de um objeto que estamos percorrendo, ele ter\u00e1 uma chave e um valor, e \u00e9 por isso que o separamos. O valor desse par tamb\u00e9m \u00e9 um objeto, que cont\u00e9m informa\u00e7\u00f5es de nome e de e-mail.<\/p>\n<p>A linha com o <strong>editar<\/strong> e <strong>excluir<\/strong> est\u00e1 obtendo informa\u00e7\u00f5es do objeto para exclu\u00ed-lo do armazenamento ou pass\u00e1-lo para uma tela diferente para que possamos edit\u00e1-lo.<\/p>\n<p>Agora vamos para a segunda e \u00faltima rota do nosso aplicativo. Abra a rota <strong>item.html<\/strong> e inclua o seguinte c\u00f3digo:<\/p>\n<pre><code class=\"language-xhtml\"><\/code><\/pre>\n<p>&nbsp;<\/p>\n<div class=\"form-group\"><label for=\"firstname\">Primeiro nome<\/label> <\/div>\n<p>&nbsp;<\/p>\n<div class=\"form-group\"><label for=\"lastname\">Sobrenome<\/label> <\/div>\n<p>&nbsp;<\/p>\n<div class=\"form-group\"><label for=\"email\">E-mail<\/label> <\/div>\n<p><button class=\"btn btn-danger\" type=\"button\">Cancelar<\/button> <button class=\"btn btn-success\" type=\"button\">Salvar<\/button><\/p>\n<p>Essencialmente, isso \u00e9 apenas um formul\u00e1rio. Temos uma fun\u00e7\u00e3o de salvamento que veremos na pr\u00f3xima se\u00e7\u00e3o sobre controladores AngularJS.<\/p>\n<h4>O servi\u00e7o AngularJS do PouchDB<\/h4>\n<p>Antes de prosseguirmos, precisamos falar sobre o servi\u00e7o AngularJS para o PouchDB. Caso contr\u00e1rio, todo o resto n\u00e3o far\u00e1 sentido. Estamos criando um servi\u00e7o porque queremos que as coisas sejam compat\u00edveis com o AngularJS no PouchDB. Queremos ter interfaces reativas, entre outras coisas. No final do <strong>app.js<\/strong> adicione o seguinte c\u00f3digo:<\/p>\n<pre><code class=\"language-javascript\">\r\n.service(\"$pouchDB\", [\"$rootScope\", \"$q\", function($rootScope, $q) {\r\n\r\n    var database;\r\n    var changeListener;\r\n\r\n    this.setDatabase = function(databaseName) {\r\n        database = new PouchDB(databaseName);\r\n    }\r\n\r\n    this.startListening = function() {\r\n        changeListener = database.changes({\r\n            live: true,\r\n            include_docs: true\r\n        }).on(\"change\", function(change) {\r\n            if(!change.deleted) {\r\n                $rootScope.$broadcast(\"$pouchDB:change\", change);\r\n            } else {\r\n                $rootScope.$broadcast(\"$pouchDB:delete\", change);\r\n            }\r\n        });\r\n    }\r\n\r\n    this.stopListening = function() {\r\n        changeListener.cancel();\r\n    }\r\n\r\n    this.sync = function(remoteDatabase) {\r\n        database.sync(remoteDatabase, {live: true, retry: true});\r\n    }\r\n\r\n    this.save = function(jsonDocument) {\r\n        var deferred = $q.defer();\r\n        if(!jsonDocument._id) {\r\n            database.post(jsonDocument).then(function(response) {\r\n                deferred.resolve(response);\r\n            }).catch(function(error) {\r\n                deferred.reject(error);\r\n            });\r\n        } else {\r\n            database.put(jsonDocument).then(function(response) {\r\n                deferred.resolve(response);\r\n            }).catch(function(error) {\r\n                deferred.reject(error);\r\n            });\r\n        }\r\n        return deferred.promise;\r\n    }\r\n\r\n    this.delete = function(documentId, documentRevision) {\r\n        return database.remove(documentId, documentRevision);\r\n    }\r\n\r\n    this.get = function(documentId) {\r\n        return database.get(documentId);\r\n    }\r\n\r\n    this.destroy = function() {\r\n        database.destroy();\r\n    }\r\n\r\n}]);\r\n<\/code><\/pre>\n<p>\u00c9 muita coisa para entender. Basicamente, estamos apenas encapsulando muitas das fun\u00e7\u00f5es do PouchDB. No entanto, o que mais importa aqui \u00e9 a fun\u00e7\u00e3o <strong>startListening<\/strong> e <strong>salvar<\/strong> fun\u00e7\u00f5es.<\/p>\n<p>Dentro do <strong>startListening<\/strong> estamos ouvindo as altera\u00e7\u00f5es e transmitindo-as pelo aplicativo usando a fun\u00e7\u00e3o <strong>$rootScope.$broadcast<\/strong>. Embora voc\u00ea ainda n\u00e3o tenha visto isso, o AngularJS pode captar essas transmiss\u00f5es usando <strong>$rootScope.$on<\/strong>. Isso facilita muito a altera\u00e7\u00e3o da interface do usu\u00e1rio.<\/p>\n<p>Em termos de <strong>salvar<\/strong> estamos verificando se um ID de documento foi passado para n\u00f3s. Se nenhum ID de documento tiver sido passado, significa que se trata de um novo documento a ser inserido; caso contr\u00e1rio, trata-se de uma atualiza\u00e7\u00e3o.<\/p>\n<h4>Voltando \u00e0 nossa fun\u00e7\u00e3o Controller and Run<\/h4>\n<p>Vamos come\u00e7ar com o AngularJS <strong>.run()<\/strong> porque ela \u00e9 curta. Adicione o seguinte c\u00f3digo:<\/p>\n<pre><code class=\"language-javascript\">\r\n.run(function($pouchDB) {\r\n    $pouchDB.setDatabase(\"nraboy-test\");\r\n    $pouchDB.sync(\"https:\/\/localhost:4984\/test-database\");\r\n})\r\n<\/code><\/pre>\n<p>Aqui, nomeamos o banco de dados local e informamos que queremos sincronizar com esse local remoto que, na verdade, \u00e9 o nosso Couchbase Sync Gateway. Essa sincroniza\u00e7\u00e3o acontece continuamente depois que a chamamos. Por cont\u00ednua, quero dizer que as altera\u00e7\u00f5es ser\u00e3o replicadas entre o aplicativo e o servidor enquanto o aplicativo estiver aberto.<\/p>\n<p>Passando para o c\u00f3digo do controlador, adicione o seguinte:<\/p>\n<pre><code class=\"language-javascript\">\r\n.controller(\"MainController\", function($scope, $rootScope, $state, $stateParams, $pouchDB) {\r\n\r\n    $scope.items = {};\r\n\r\n    $pouchDB.startListening();\r\n\r\n    $rootScope.$on(\"$pouchDB:change\", function(event, data) {\r\n        $scope.items[data.doc._id] = data.doc;\r\n        $scope.$apply();\r\n    });\r\n\r\n    $rootScope.$on(\"$pouchDB:delete\", function(event, data) {\r\n        delete $scope.items[data.doc._id];\r\n        $scope.$apply();\r\n    });\r\n\r\n    if($stateParams.documentId) {\r\n        $pouchDB.get($stateParams.documentId).then(function(result) {\r\n            $scope.inputForm = result;\r\n        });\r\n    }\r\n\r\n    $scope.save = function(firstname, lastname, email) {\r\n        var jsonDocument = {\r\n            \"firstname\": firstname,\r\n            \"lastname\": lastname,\r\n            \"email\": email\r\n        };\r\n        if($stateParams.documentId) {\r\n            jsonDocument[\"_id\"] = $stateParams.documentId;\r\n            jsonDocument[\"_rev\"] = $stateParams.documentRevision;\r\n        }\r\n        $pouchDB.save(jsonDocument).then(function(response) {\r\n            $state.go(\"list\");\r\n        }, function(error) {\r\n            console.log(\"ERROR -&gt; \" + error);\r\n        });\r\n    }\r\n\r\n    $scope.delete = function(id, rev) {\r\n        $pouchDB.delete(id, rev);\r\n    }\r\n\r\n})\r\n<\/code><\/pre>\n<p>O aplicativo j\u00e1 est\u00e1 sendo sincronizado, portanto, precisamos ouvir as altera\u00e7\u00f5es. Aqui est\u00e1 o <strong>$rootScope.$on<\/strong> Eu mencionei anteriormente. Temos dois deles porque em um estamos ouvindo altera\u00e7\u00f5es (cria\u00e7\u00e3o ou atualiza\u00e7\u00e3o) e no outro estamos ouvindo exclus\u00f5es.<\/p>\n<p>Se o <strong>list.html<\/strong> Se a p\u00e1gina nos encaminhou at\u00e9 aqui para uma atualiza\u00e7\u00e3o, ent\u00e3o teremos um ID de documento passado. Nesse cen\u00e1rio, podemos fazer uma pesquisa e obter os dados desse ID de documento espec\u00edfico para exibir no formul\u00e1rio, em vez de deix\u00e1-lo em branco, que \u00e9 o padr\u00e3o.<\/p>\n<p>Finalmente, temos nosso <strong>salvar<\/strong> e <strong>excluir<\/strong> fun\u00e7\u00f5es.<\/p>\n<h2>Configura\u00e7\u00e3o do Sync Gateway<\/h2>\n<p>O PouchDB e o AngularJS s\u00e3o apenas a metade da hist\u00f3ria aqui. \u00c9 claro que eles criar\u00e3o um bom aplicativo executado localmente, mas queremos que as coisas sejam sincronizadas. O Couchbase Sync Gateway \u00e9 nosso ponto de extremidade para isso e, \u00e9 claro, o PouchDB funciona muito bem com ele.<\/p>\n<p>Dentro da se\u00e7\u00e3o <strong>sync-gateway-config.json<\/strong> adicione o seguinte:<\/p>\n<pre><code class=\"language-json\">\r\n{\r\n    \"log\":[\"CRUD+\", \"REST+\", \"Changes+\", \"Attach+\"],\r\n    \"databases\": {\r\n        \"test-database\": {\r\n            \"server\":\"walrus:data\",\r\n            \"sync\":`\r\n                function (doc) {\r\n                    channel (doc.channels);\r\n                }\r\n            `,\r\n            \"users\": {\r\n                \"GUEST\": {\r\n                    \"disabled\": false,\r\n                    \"admin_channels\": [\"*\"]\r\n                }\r\n            }\r\n        }\r\n    },\r\n    \"CORS\": {\r\n        \"Origin\": [\"https:\/\/localhost:9000\"],\r\n        \"LoginOrigin\": [\"https:\/\/localhost:9000\"],\r\n        \"Headers\": [\"Content-Type\"],\r\n        \"MaxAge\": 17280000\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>Essa \u00e9 uma das configura\u00e7\u00f5es mais b\u00e1sicas existentes. Algumas observa\u00e7\u00f5es sobre ela:<\/p>\n<ul>\n<li>Ele usa walrus:data para armazenamento, que fica na mem\u00f3ria e n\u00e3o persiste. N\u00e3o deve ser usado para produ\u00e7\u00e3o.<\/li>\n<li>Todos os dados s\u00e3o sincronizados por meio do usu\u00e1rio GUEST, portanto, n\u00e3o h\u00e1 autentica\u00e7\u00e3o acontecendo aqui, mas poderia haver<\/li>\n<li>Estamos corrigindo problemas de CORS ao permitir solicita\u00e7\u00f5es em localhost:9000<\/li>\n<\/ul>\n<h2>Testando o aplicativo<\/h2>\n<p>Neste ponto, todo o nosso c\u00f3digo est\u00e1 no lugar e o Sync Gateway est\u00e1 pronto para ser executado. Inicie o Sync Gateway executando o seguinte em um prompt de comando ou terminal:<\/p>\n<pre><code class=\"language-bash\">\/path\/to\/sync\/gateway\/bin\/sync-gateway \/path\/to\/project\/sync-gateway-config.json<\/code><\/pre>\n<p>\u00c9 aqui que o Python entra em a\u00e7\u00e3o. N\u00e3o \u00e9 poss\u00edvel simplesmente abrir os arquivos HTML em um navegador da Web. Eles devem ser servidos para evitar problemas de CORS. No prompt de comando ou terminal, com o projeto como seu diret\u00f3rio de trabalho atual, execute o seguinte:<\/p>\n<pre><code class=\"language-bash\">python -m SimpleHTTPServer 9000<\/code><\/pre>\n<p>Acesse https:\/\/localhost:9000 em seu navegador da Web e confira!<\/p>\n<h2>Conclus\u00e3o<\/h2>\n<p>Agora voc\u00ea viu como criar um aplicativo da Web que pode ser sincronizado com o Couchbase usando nada mais do que AngularJS e PouchDB. N\u00e3o foram necess\u00e1rios SDKs de back-end.<\/p>\n<p>Voc\u00ea pode obter o c\u00f3digo-fonte completo desta postagem do blog por meio de nosso <a href=\"https:\/\/github.com\/couchbaselabs\/pouchdb-angularjs-app\" target=\"_blank\" rel=\"noopener\">Reposit\u00f3rio do GitHub do Couchbase Labs<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>There are many ways to use Couchbase in your web or mobile application through one of the various language SDKs. However, what if you were not using a backend language such as PHP or a mobile language such as Objective-C? [&hellip;]<\/p>","protected":false},"author":63,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[9327,2366],"tags":[1542,1543,1541],"ppma_author":[9032],"class_list":["post-2083","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-javascript","category-sync-gateway","tag-angularjs","tag-javascript","tag-pouchdb"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.2 (Yoast SEO v26.2) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Sync With Couchbase Using Only AngularJS And PouchDB<\/title>\n<meta name=\"description\" content=\"Learn how to create a web application that can sync with Couchbase using nothing more than AngularJS and PouchDB. No backend SDKs were required.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/pt\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Sync With Couchbase Using Only AngularJS And PouchDB\" \/>\n<meta property=\"og:description\" content=\"Learn how to create a web application that can sync with Couchbase using nothing more than AngularJS and PouchDB. No backend SDKs were required.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/pt\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/thepolyglotdeveloper\" \/>\n<meta property=\"article:published_time\" content=\"2015-09-30T18:22:46+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T06:54:07+00:00\" \/>\n<meta name=\"author\" content=\"Nic Raboy, Developer Advocate, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@nraboy\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Nic Raboy, Developer Advocate, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/\"},\"author\":{\"name\":\"Nic Raboy, Developer Advocate, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1\"},\"headline\":\"Sync With Couchbase Using Only AngularJS And PouchDB\",\"datePublished\":\"2015-09-30T18:22:46+00:00\",\"dateModified\":\"2025-06-14T06:54:07+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/\"},\"wordCount\":1627,\"commentCount\":41,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"keywords\":[\"angularjs\",\"javascript\",\"pouchdb\"],\"articleSection\":[\"JavaScript\",\"Sync Gateway\"],\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/\",\"name\":\"Sync With Couchbase Using Only AngularJS And PouchDB\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2015-09-30T18:22:46+00:00\",\"dateModified\":\"2025-06-14T06:54:07+00:00\",\"description\":\"Learn how to create a web application that can sync with Couchbase using nothing more than AngularJS and PouchDB. No backend SDKs were required.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/#breadcrumb\"},\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"width\":1800,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Sync With Couchbase Using Only AngularJS And PouchDB\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"pt-BR\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1\",\"name\":\"Nic Raboy, Developer Advocate, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/8863514d8bed0cf6080f23db40e00354\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g\",\"caption\":\"Nic Raboy, Developer Advocate, Couchbase\"},\"description\":\"Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.\",\"sameAs\":[\"https:\/\/www.thepolyglotdeveloper.com\",\"https:\/\/www.facebook.com\/thepolyglotdeveloper\",\"https:\/\/x.com\/nraboy\"],\"url\":\"https:\/\/www.couchbase.com\/blog\/pt\/author\/nic-raboy-2\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Sincroniza\u00e7\u00e3o com o Couchbase usando apenas AngularJS e PouchDB","description":"Saiba como criar um aplicativo da Web que pode ser sincronizado com o Couchbase usando apenas AngularJS e PouchDB. N\u00e3o foram necess\u00e1rios SDKs de back-end.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/pt\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/","og_locale":"pt_BR","og_type":"article","og_title":"Sync With Couchbase Using Only AngularJS And PouchDB","og_description":"Learn how to create a web application that can sync with Couchbase using nothing more than AngularJS and PouchDB. No backend SDKs were required.","og_url":"https:\/\/www.couchbase.com\/blog\/pt\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/","og_site_name":"The Couchbase Blog","article_author":"https:\/\/www.facebook.com\/thepolyglotdeveloper","article_published_time":"2015-09-30T18:22:46+00:00","article_modified_time":"2025-06-14T06:54:07+00:00","author":"Nic Raboy, Developer Advocate, Couchbase","twitter_card":"summary_large_image","twitter_creator":"@nraboy","twitter_misc":{"Written by":"Nic Raboy, Developer Advocate, Couchbase","Est. reading time":"9 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/"},"author":{"name":"Nic Raboy, Developer Advocate, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1"},"headline":"Sync With Couchbase Using Only AngularJS And PouchDB","datePublished":"2015-09-30T18:22:46+00:00","dateModified":"2025-06-14T06:54:07+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/"},"wordCount":1627,"commentCount":41,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","keywords":["angularjs","javascript","pouchdb"],"articleSection":["JavaScript","Sync Gateway"],"inLanguage":"pt-BR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/","url":"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/","name":"Sincroniza\u00e7\u00e3o com o Couchbase usando apenas AngularJS e PouchDB","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2015-09-30T18:22:46+00:00","dateModified":"2025-06-14T06:54:07+00:00","description":"Saiba como criar um aplicativo da Web que pode ser sincronizado com o Couchbase usando apenas AngularJS e PouchDB. N\u00e3o foram necess\u00e1rios SDKs de back-end.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/#breadcrumb"},"inLanguage":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/"]}]},{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","width":1800,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/sync-with-couchbase-using-only-angularjs-and-pouchdb\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Sync With Couchbase Using Only AngularJS And PouchDB"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"Blog do Couchbase","description":"Couchbase, o banco de dados NoSQL","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"pt-BR"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"Blog do Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1","name":"Nic Raboy, defensor dos desenvolvedores, Couchbase","image":{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/8863514d8bed0cf6080f23db40e00354","url":"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g","caption":"Nic Raboy, Developer Advocate, Couchbase"},"description":"Nic Raboy \u00e9 um defensor das modernas tecnologias de desenvolvimento m\u00f3vel e da Web. Ele tem experi\u00eancia em Java, JavaScript, Golang e uma variedade de estruturas, como Angular, NativeScript e Apache Cordova. Nic escreve sobre suas experi\u00eancias de desenvolvimento relacionadas a tornar o desenvolvimento m\u00f3vel e da Web mais f\u00e1cil de entender.","sameAs":["https:\/\/www.thepolyglotdeveloper.com","https:\/\/www.facebook.com\/thepolyglotdeveloper","https:\/\/x.com\/nraboy"],"url":"https:\/\/www.couchbase.com\/blog\/pt\/author\/nic-raboy-2\/"}]}},"authors":[{"term_id":9032,"user_id":63,"is_guest":0,"slug":"nic-raboy-2","display_name":"Nic Raboy, Developer Advocate, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g","author_category":"","last_name":"Raboy","first_name":"Nic","job_title":"","user_url":"https:\/\/www.thepolyglotdeveloper.com","description":"Nic Raboy \u00e9 um defensor das modernas tecnologias de desenvolvimento m\u00f3vel e da Web. Ele tem experi\u00eancia em Java, JavaScript, Golang e uma variedade de estruturas, como Angular, NativeScript e Apache Cordova. Nic escreve sobre suas experi\u00eancias de desenvolvimento relacionadas a tornar o desenvolvimento m\u00f3vel e da Web mais f\u00e1cil de entender."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/2083","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/users\/63"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/comments?post=2083"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/2083\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media?parent=2083"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/categories?post=2083"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/tags?post=2083"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/ppma_author?post=2083"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}