{"id":2456,"date":"2016-12-15T15:00:00","date_gmt":"2016-12-15T15:00:00","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=2456"},"modified":"2025-06-13T20:15:37","modified_gmt":"2025-06-14T03:15:37","slug":"data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/es\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/","title":{"rendered":"Sincronizaci\u00f3n de datos con Couchbase en aplicaciones m\u00f3viles h\u00edbridas Ionic 2"},"content":{"rendered":"<p>El a\u00f1o pasado escrib\u00ed sobre el uso de <a href=\"https:\/\/www.couchbase.com\/blog\/es\/using-couchbase-in-your-ionic-framework-application-part-1\/\">Couchbase Mobile en una aplicaci\u00f3n m\u00f3vil de Ionic Framework<\/a>. Por aquel entonces us\u00e1bamos Ionic Framework 1.0 y AngularJS 1.0. La tecnolog\u00eda ha cambiado con el paso de los meses y hemos pasado de lo que parecen frameworks antiguos a iteraciones mucho m\u00e1s modernas.<\/p>\n<p>Con Angular 2 liberado y Ionic 2 cerca del lanzamiento estable, pens\u00e9 que ser\u00eda una gran idea revisar lo que hab\u00eda hecho anteriormente y explorar Couchbase Mobile en una aplicaci\u00f3n Android y iOS Ionic 2.<\/p>\n<h2 id=\"the-requirements\">Requisitos<\/h2>\n<p>Para hacer posible este proyecto vamos a necesitar algunas cosas instaladas y disponibles. Son las siguientes:<\/p>\n<ul>\n<li>Node.js 4.0+<\/li>\n<li>Marco Ionic 2.0<\/li>\n<li>El SDK de Android o Xcode<\/li>\n<li>Pasarela de sincronizaci\u00f3n Couchbase<\/li>\n<\/ul>\n<p>Ionic Framework utiliza el Node Package Manager (NPM) que viene con Node.js para manejar todas las dependencias del proyecto. Para construir aplicaciones Android necesitaremos el SDK de Android instalado y para construir aplicaciones iOS necesitaremos un Mac con Xcode instalado. Por \u00faltimo, si queremos demostrar la sincronizaci\u00f3n, necesitaremos Couchbase Sync Gateway instalado y disponible.<\/p>\n<h2 id=\"creating-a-new-ionic-2-project\">Creaci\u00f3n de un nuevo proyecto Ionic 2<\/h2>\n<p>Vamos a construir una aplicaci\u00f3n de lista de tareas muy simple con Ionic 2, Angular 2 y TypeScript. Esta lista de tareas se sincronizar\u00e1 entre dispositivos y plataformas como se muestra en la imagen animada de abajo.<\/p>\n<div class=\"figure\"><img decoding=\"async\" src=\"\/wp-content\/original-assets\/2016\/december\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/ionic-2-couchbase.gif\" alt=\"Ionic 2 with Couchbase\" \/><\/div>\n<p>Esta es la misma aplicaci\u00f3n que vimos en el tutorial de Ionic Framework 1.0 as\u00ed como muchas otras <a href=\"https:\/\/www.couchbase.com\/blog\/es\/mobile-tutorials\/\">tutoriales para m\u00f3viles<\/a>. Es la misma aplicaci\u00f3n porque sirve de ejemplo muy \u00fatil.<\/p>\n<p>Para simplificar las cosas, vamos a empezar con un proyecto nuevo. Desde el s\u00edmbolo del sistema (Windows) o Terminal (Linux y Mac), ejecute lo siguiente:<\/p>\n<pre><code>ionic start CouchbaseProject blank --v2\r\ncd CouchbaseProject\r\nionic platform add ios\r\nionic platform add android<\/code><\/pre>\n<p>Los comandos anteriores crear\u00e1n un proyecto Ionic Framework 2.0 que utiliza Angular 2 y TypeScript. Aunque he elegido a\u00f1adir las plataformas de compilaci\u00f3n iOS y Android, no podremos compilar para iOS a menos que estemos usando un Mac con Xcode instalado.<\/p>\n<p>Este proyecto depende de la <a href=\"https:\/\/github.com\/couchbaselabs\/Couchbase-Lite-PhoneGap-Plugin\">Plugin PhoneGap de Couchbase<\/a> para funcionar. No te alarmes. Aunque el nombre dice PhoneGap, en realidad no es m\u00e1s que un plugin de Apache Cordova, algo que es muy compatible con Ionic 2. Para instalar este plugin en el proyecto, ejecuta lo siguiente:<\/p>\n<pre><code>ionic plugin add https:\/\/github.com\/couchbaselabs\/Couchbase-Lite-PhoneGap-Plugin.git<\/code><\/pre>\n<p>El plugin de Couchbase Lite para Apache Cordova funciona completamente con las APIs RESTful que est\u00e1n disponibles. Personalmente preferir\u00eda no trabajar con APIs en mi aplicaci\u00f3n, as\u00ed que constru\u00ed una bonita envoltura JavaScript para convertir las APIs en una clase agradable. La envoltura,<a href=\"https:\/\/github.com\/couchbaselabs\/cordova-couchbase\">cordova-couchbase<\/a>le permitir\u00e1 utilizar m\u00e9todos en lugar de preocuparse por las solicitudes HTTP a los puntos finales.<\/p>\n<p>Para instalar cordova-couchbase en su proyecto, ejecute lo siguiente:<\/p>\n<pre><code>npm install cordova-couchbase --save<\/code><\/pre>\n<p>En este punto estamos listos para empezar a desarrollar la aplicaci\u00f3n Ionic 2.<\/p>\n<h2 id=\"managing-couchbase-via-an-angular-2-provider\">Gesti\u00f3n de Couchbase a trav\u00e9s de un proveedor de Angular 2<\/h2>\n<p>Cuando se trabaja con bases de datos en una aplicaci\u00f3n Angular 2, es una buena idea mantenerlas en un servicio, tambi\u00e9n conocido como proveedor. Esto nos permite no solo arrancar gran parte de la l\u00f3gica de la base de datos en un \u00fanico archivo, sino mantener nuestra capa de base de datos segregada del resto de nuestro c\u00f3digo.<\/p>\n<p>Usando la CLI de Ionic, ejecuta lo siguiente para generar una clase de proveedor:<\/p>\n<pre><code>ionic g provider CouchbaseProvider<\/code><\/pre>\n<p>B\u00e1sicamente, el comando s\u00f3lo crea un directorio y un archivo en <strong>src\/providers\/couchbase-provider.ts<\/strong> dentro del proyecto. Este proveedor deber\u00eda tener un aspecto similar al siguiente:<\/p>\n<pre class=\"whitespace-after:1 lang:default decode:true\"><code>import { Injectable } from '@angular\/core';\r\nimport { Http } from '@angular\/http';\r\nimport { Platform } from 'ionic-angular';\r\nimport { Couchbase, Database } from 'cordova-couchbase\/core';\r\nimport 'rxjs\/add\/operator\/map'; \r\n\r\n@Injectable()\r\nexport class CouchbaseProvider {\r\n    public constructor(public http:Http) { }\r\n}<\/code><\/pre>\n<p>Empecemos a pensar en c\u00f3mo funcionar\u00e1 nuestro servicio Couchbase y en las piezas de c\u00f3digo que lo integrar\u00e1n para que sea un \u00e9xito.<\/p>\n<p>Queremos que nuestro servicio de base de datos act\u00fae como un singleton, lo que significa que queremos que se instancie una \u00fanica clase de base de datos para toda la aplicaci\u00f3n. Algo as\u00ed como un servicio compartido. Podemos configurar esto a trav\u00e9s de la <code>constructor<\/code> de nuestro proveedor:<\/p>\n<pre class=\"whitespace-after:1 lang:js decode:true\">private isInstantiated:boolean;\r\nprivate database:Database;\r\npublic constructor(public http:Http, platform:Platform) {\r\n    if(!this.isInstantiated) {\r\n        platform.ready().then(() =&gt; {\r\n            (new Couchbase()).openDatabase(\"nraboy\").then(database =&gt; {\r\n                this.database = database; \r\n                this.isInstantiated = true;\r\n            }, error =&gt; {\r\n                console.error(error);\r\n            });\r\n        });\r\n    }\r\n}<\/pre>\n<p>Entonces, \u00bfqu\u00e9 est\u00e1 pasando en el c\u00f3digo anterior hasta ahora? Primero creamos dos variables privadas. La booleana nos dir\u00e1 si la base de datos ya ha sido instanciada. La <code>Base de datos<\/code> contendr\u00e1 la base de datos abierta en ese momento.<\/p>\n<p>Dentro de la <code>constructor<\/code> estamos haciendo nuestra comprobaci\u00f3n l\u00f3gica condicional. Debido a que el plugin de Apache Cordova utiliza c\u00f3digo nativo necesitamos asegurarnos de que el dispositivo est\u00e1 listo. Esto se demuestra mediante el uso de Ionic's <code>plataforma.lista<\/code> m\u00e9todo. Una vez que el dispositivo est\u00e1 listo podemos abrir una base de datos, incluso si no existe, y establecerla en nuestra variable privada.<\/p>\n<pre><code>public getDatabase() {\r\n    return this.database;\r\n}<\/code><\/pre>\n<p>La base de datos abierta puede recuperarse de nuestro proveedor utilizando el m\u00e9todo anterior <code>getDatabase<\/code> m\u00e9todo.<\/p>\n<p>No hemos terminado con el <code>CouchbaseProvider<\/code> todav\u00eda. Probablemente deber\u00edamos pensar en crear nuestras vistas MapReduce para futuras consultas y configurar nuestro escuchador de cambios. Todo esto ocurrir\u00e1 dentro de la clase <code>constructor<\/code> despu\u00e9s de establecer la base de datos abierta.<\/p>\n<p>Por ejemplo, veamos lo siguiente:<\/p>\n<pre class=\"whitespace-after:1 lang:default decode:true\">private isInstantiated:boolean;\r\nprivate database:Database;\r\nprivate listener:EventEmitter = new EventEmitter();\r\n \r\npublic constructor(public http:Http, platform:Platform) {\r\n    if(!this.isInstantiated) {\r\n        platform.ready().then(() =&gt; {\r\n            (new Couchbase()).openDatabase(\"nraboy\").then(database =&gt; {\r\n                this.database = database;\r\n                let views = {\r\n                    items: {\r\n                        map:function(doc) {\r\n                            if (doc.type == \"list\" &amp;&amp; doc.title) {\r\n                                emit(doc._id,{ title: doc.title, rev: doc._rev })\r\n                            }\r\n                        }.toString()\r\n                    }\r\n                };\r\n                this.database.createDesignDocument(\"_design\/todo\", views);\r\n                this.database.listen(change =&gt; {\r\n                    this.listener.emit(change.detail);\r\n                });\r\n                this.isInstantiated = true;\r\n            },error =&gt; {\r\n                console.error(error);\r\n            });\r\n        });\r\n    }\r\n}<\/pre>\n<p>En el c\u00f3digo anterior hemos a\u00f1adido un <code>oyente<\/code> que emitir\u00e1 cambios a los que podremos suscribirnos en nuestro c\u00f3digo Angular 2. Dentro de la variable <code>constructor<\/code> creamos una vista MapReduce llamada <code>art\u00edculos<\/code> con una l\u00f3gica que emitir\u00e1 pares clave-valor s\u00f3lo si el documento contiene una propiedad llamada <code>tipo<\/code> que es igual a \"list\" y una propiedad llamada <code>t\u00edtulo<\/code> que puede equivaler a cualquier cosa.<\/p>\n<p>A continuaci\u00f3n, la vista se a\u00f1ade a un documento de dise\u00f1o de nuestra elecci\u00f3n y se activa la escucha. Con el listener activado, cualquier cambio en la base de datos lo activar\u00e1. Esto significa que si a\u00f1adimos un documento, cambiamos un documento, o borramos un documento, el listener emitir\u00e1 el cambio.<\/p>\n<pre><code>public getChangeListener(): EventEmitter {\r\n    return this.listener;\r\n}<\/code><\/pre>\n<p>Se puede acceder a la escucha desde varias p\u00e1ginas de la aplicaci\u00f3n llamando a la funci\u00f3n <code>getChangeListener<\/code> funci\u00f3n.<\/p>\n<p>El proveedor est\u00e1 creado, pero actualmente no est\u00e1 siendo compartido a trav\u00e9s de la aplicaci\u00f3n. Para ello tenemos que importarlo en el Angular 2 <code>@NgModule<\/code> que se encuentra en el bloque <strong>src\/app\/app.module.ts<\/strong> archivo. Este archivo tendr\u00e1 un aspecto similar al siguiente una vez terminado:<\/p>\n<pre><code>import { NgModule, ErrorHandler } from '@angular\/core';\r\nimport { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';\r\nimport { MyApp } from '.\/app.component';\r\nimport { HomePage } from '..\/pages\/home\/home';\r\n\r\nimport { CouchbaseProvider } from \"..\/providers\/couchbase-provider\";\r\n\r\n@NgModule({\r\n    declarations: [\r\n        MyApp,\r\n        HomePage\r\n    ],\r\n    imports: [\r\n        IonicModule.forRoot(MyApp)\r\n    ],\r\n    bootstrap: [IonicApp],\r\n    entryComponents: [\r\n        MyApp,\r\n        HomePage\r\n    ],\r\n    providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}, CouchbaseProvider]\r\n})\r\nexport class AppModule {}<\/code><\/pre>\n<p>Observe que el proveedor se ha importado y a\u00f1adido al <code>proveedores<\/code> array? Ahora podemos centrarnos en a\u00f1adir l\u00f3gica de aplicaci\u00f3n.<\/p>\n<h2 id=\"using-couchbase-within-the-ionic-2-application\">Uso de Couchbase en la aplicaci\u00f3n Ionic 2<\/h2>\n<p>Probablemente sea una buena idea abrir nuestra base de datos cuando se inicie la aplicaci\u00f3n. Aunque podr\u00edamos hacerlo cuando se carga la primera p\u00e1gina, no es necesario.<\/p>\n<p>Abra el archivo <strong>src\/app\/app.component.ts<\/strong> e incluya el siguiente c\u00f3digo TypeScript:<\/p>\n<pre class=\"whitespace-after:1 lang:js decode:true\">import { Component } from '@angular\/core';\r\nimport { Platform } from 'ionic-angular';\r\nimport { StatusBar, Splashscreen } from 'ionic-native';\r\n\r\nimport { HomePage } from '..\/pages\/home\/home';\r\nimport { CouchbaseProvider } from \"..\/providers\/couchbase-provider\";\r\n\r\n@Component({\r\n    templateUrl: 'app.html'\r\n})\r\nexport class MyApp {\r\n    rootPage = HomePage;\r\n    constructor(platform: Platform, couchbase: CouchbaseProvider) { \r\n        platform.ready().then(() =&gt; {\r\n            StatusBar.styleDefault(); \r\n            Splashscreen.hide();\r\n        });\r\n    }\r\n}<\/pre>\n<p>En el c\u00f3digo anterior hemos importado el proveedor y lo hemos inyectado en el archivo <code>constructor<\/code> m\u00e9todo. Esto se activar\u00e1 antes de que se cargue la primera p\u00e1gina, se abra la base de datos, se cree la vista y se inicie el listener.<\/p>\n<p>De aqu\u00ed en adelante vamos a pasar nuestro tiempo en la primera y \u00fanica p\u00e1gina de la aplicaci\u00f3n. Esto significa que vamos a pasar nuestro tiempo en el proyecto de <strong>src\/pages\/home\/home.ts<\/strong> y <strong>src\/pages\/home\/home.html<\/strong> archivos.<\/p>\n<p>Abra el archivo <strong>src\/pages\/home\/home.ts<\/strong> e incluya el siguiente c\u00f3digo:<\/p>\n<pre><code>import { Component, NgZone } from '@angular\/core';\r\nimport { NavController, AlertController } from 'ionic-angular';\r\nimport { CouchbaseProvider } from \"..\/..\/providers\/couchbase-provider\";\r\n\r\n@Component({\r\n    selector: 'page-home',\r\n    templateUrl: 'home.html'\r\n})\r\nexport class HomePage {\r\n\r\n    public items: Array;\r\n\r\n    public constructor(public navCtrl: NavController, public alertCtrl: AlertController, public couchbase: CouchbaseProvider, public zone: NgZone) {\r\n        this.items = [];\r\n    }\r\n\r\n    public ionViewDidEnter() { }\r\n\r\n    public refresh() { }\r\n\r\n    public add() { }\r\n\r\n}<\/code><\/pre>\n<p>Vamos a desglosar lo que esto significa y a\u00f1adir cada uno de los m\u00e9todos uno por uno.<\/p>\n<p>Puedes ver que estamos importando el archivo <code>CouchbaseProvider<\/code> junto con otros componentes. Exploraremos lo que significa cada uno a medida que vayamos llegando.<\/p>\n<p>En <code>art\u00edculos<\/code> que es p\u00fablico contendr\u00e1 todos nuestros todo-elementos que se presentar\u00e1n en la interfaz de usuario, de ah\u00ed por qu\u00e9 es p\u00fablico. El <code>constructor<\/code> tiene muchas inyecciones para cada uno de los componentes que planeamos usar. Tambi\u00e9n es donde inicializamos nuestro array p\u00fablico.<\/p>\n<p>Nunca es aconsejable cargar datos en el <code>constructor<\/code> por lo que tenemos el m\u00e9todo <code>ionViewDidEnter<\/code> m\u00e9todo. En este m\u00e9todo es donde se realiza la mayor parte del trabajo pesado:<\/p>\n<pre class=\"whitespace-after:1 lang:js decode:true\">public ionViewDidEnter() {\r\n    setTimeout(() =&gt; {\r\n        this.couchbase.getChangeListener().subscribe(data =&gt; {\r\n            for(let i = 0; i &lt; data.length; i++) {\r\n                if(!data[i].hasOwnProperty(\"deleted\") &amp;&amp; data[i].id.indexOf(\"_design\") === -1) {\r\n                    this.couchbase.getDatabase().getDocument(data[i].id).then(result =&gt; {\r\n                        if(result.type === \"list\") {\r\n                            this.zone.run(() =&gt; {\r\n                                this.items.push(result);\r\n                            });\r\n                        }\r\n                    });\r\n                }\r\n            }\r\n        });\r\n        this.refresh();\r\n    }, 100);\r\n}<\/pre>\n<p>Primero notar\u00e1s el tiempo de espera. Estamos trabajando con muchos componentes as\u00edncronos, espec\u00edficamente el componente Couchbase. A menudo hay una condici\u00f3n de carrera donde la base de datos no estar\u00e1 lista a tiempo para cuando queramos usarla. A\u00f1adir un simple timeout de 100ms es m\u00e1s que suficiente para que la bola empiece a rodar. Hay otras maneras de hacer esto, pero el timeout es mi preferencia.<\/p>\n<p>Cuando se carga la p\u00e1gina queremos suscribirnos a nuestro listener creado en el proveedor. Cualquier dato emitido lo recorreremos en bucle. En este ejemplo en particular estamos ignorando los borrados y tratando los cambios y adiciones de la misma manera. En tu aplicaci\u00f3n puede que quieras a\u00f1adir una l\u00f3gica m\u00e1s espec\u00edfica. Esencialmente estoy diciendo que siempre y cuando el cambio no fue un borrado, vamos a tomar la clave que se cambi\u00f3 y hacer una b\u00fasqueda en el documento. Si el documento es uno de nuestros documentos todo lo que queremos a\u00f1adir a la matriz p\u00fablica.<\/p>\n<p>\u00bfQu\u00e9 est\u00e1 pasando con el <code>zona<\/code> \u00bfcosas? Los emisores pueden ponerse raros as\u00ed que cuando recibimos un evento, queremos actualizar la zona de Angular 2. Puede que esto no te parezca necesario, pero si la interfaz de usuario no se actualiza con los cambios, no tener el <code>zona<\/code> cosas es por qu\u00e9.<\/p>\n<p>Una vez creado el receptor de cambios, queremos consultar la base de datos tal y como est\u00e1 ahora. Aqu\u00ed es donde el <code>actualizar<\/code> entra en juego:<\/p>\n<pre class=\"whitespace-after:1 lang:js decode:true\">public refresh() {\r\n    this.couchbase.getDatabase().queryView(\"_design\/todo\", \"items\", {}).then(result =&gt; {\r\n        this.items = [];\r\n        for(var i = 0; i &lt; result.rows.length; i++) { this.items.push(result.rows[i].value); } }, error =&gt; {\r\n        console.error(\"ERROR: \" + JSON.stringify(error));\r\n    });\r\n}<\/pre>\n<p>En <code>actualizar<\/code> consultar\u00e1 nuestra vista y a\u00f1adir\u00e1 cada uno de los elementos resultantes a nuestro array p\u00fablico. S\u00f3lo tenemos que consultar una vez porque los cambios que vienen en se a\u00f1adir\u00e1n autom\u00e1ticamente para nosotros como una conveniencia.<\/p>\n<p>En <code>a\u00f1ada<\/code> es el m\u00e9todo final de esta p\u00e1gina Ionic 2:<\/p>\n<pre class=\"whitespace-after:1 lang:js decode:true\">public add() {\r\n    let prompt = this.alertCtrl.create({\r\n        title: 'Todo Items',\r\n        message: \"Add a new item to the todo list\",\r\n        inputs: [\r\n            {\r\n                name: 'title',\r\n                placeholder: 'Title'\r\n            },\r\n        ],\r\n        buttons: [\r\n            {\r\n                text: 'Cancel',\r\n                handler: data =&gt; {}\r\n            },\r\n            {\r\n                text: 'Save',\r\n                handler: data =&gt; {\r\n                    this.couchbase.getDatabase().createDocument({type: \"list\", title: data.title});\r\n                }\r\n            }\r\n        ]\r\n    });\r\n    prompt.present();\r\n}<\/pre>\n<p>Cuando se ejecute, aparecer\u00e1 un mensaje. Cuando el usuario introduzca informaci\u00f3n en el prompt, se guardar\u00e1 como un documento dentro de Couchbase. El receptor de cambios recoger\u00e1 este cambio local y lo a\u00f1adir\u00e1 a la lista.<\/p>\n<p>La sencilla interfaz de usuario de esta aplicaci\u00f3n, que se encuentra en la secci\u00f3n <strong>src\/pages\/home\/home.html<\/strong> tiene el siguiente aspecto:<\/p>\n<pre class=\"lang:default decode:true\">&lt;ion-header&gt;\r\n    &lt;ion-navbar&gt;\r\n        &lt;ion-title&gt;\r\n            Couchbase w\/ Ionic 2\r\n        &lt;\/ion-title&gt;\r\n        &lt;ion-buttons end&gt;\r\n            &lt;button ion-button icon-only (click)=\"add()\"&gt;\r\n                &lt;ion-icon name=\"add\"&gt;&lt;\/ion-icon&gt;\r\n            &lt;\/button&gt;\r\n        &lt;\/ion-buttons&gt;\r\n    &lt;\/ion-navbar&gt;\r\n&lt;\/ion-header&gt;\r\n\r\n&lt;ion-content padding&gt;\r\n    &lt;ion-list&gt;\r\n        &lt;ion-item *ngFor=\"let item of items\"&gt;\r\n            {{ item.title }}\r\n        &lt;\/ion-item&gt;\r\n    &lt;\/ion-list&gt;\r\n&lt;\/ion-content&gt;<\/pre>\n<p>La interfaz de usuario tiene una barra de acci\u00f3n con un bot\u00f3n para mostrar el aviso. El contenido principal es una vista de lista en la que recorremos la matriz p\u00fablica del archivo TypeScript.<\/p>\n<h2 id=\"synchronization-between-devices-and-platforms\">Sincronizaci\u00f3n entre dispositivos y plataformas<\/h2>\n<p>Hasta ahora todo ha sido local a un dispositivo. Nada de lo que hemos a\u00f1adido hasta ahora se ha encargado de la sincronizaci\u00f3n con Couchbase Sync Gateway u otros dispositivos. Sin embargo, a\u00f1adir soporte de sincronizaci\u00f3n apenas requiere esfuerzo.<\/p>\n<p>Abra el archivo <strong>src\/providers\/couchbase-provider.ts<\/strong> e incluya la siguiente l\u00ednea despu\u00e9s de abrir la base de datos:<\/p>\n<pre><code>this.database.sync(\"https:\/\/192.168.57.1:4984\/example\", true);<\/code><\/pre>\n<p>Por supuesto, cambie el nombre de host y el nombre de la base de datos por los de su instancia remota de Sync Gateway. Ahora su aplicaci\u00f3n se sincronizar\u00e1 continuamente. \u00bfNo es incre\u00edble que una l\u00ednea de c\u00f3digo nos dio soporte de sincronizaci\u00f3n?<\/p>\n<p>Si desea crear una instancia sencilla de Sync Gateway, aqu\u00ed y ahora, cree lo siguiente <strong>sync-gateway-config.json<\/strong> file:<\/p>\n<pre><code>{\r\n    \"log\":[\"CRUD+\", \"REST+\", \"Changes+\", \"Attach+\"],\r\n    \"databases\": {\r\n        \"example\": {\r\n            \"server\":\"walrus:\",\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}<\/code><\/pre>\n<p>Cuando inicie Sync Gateway, dir\u00edjalo a ese archivo de configuraci\u00f3n concreto. Actualice su <code>sincronizar<\/code> en la aplicaci\u00f3n Ionic 2 para que coincida con el host y la base de datos.<\/p>\n<h2 id=\"taking-the-finished-project-for-a-test-drive\">Probar el proyecto terminado<\/h2>\n<p>Comprendo que esta gu\u00eda sea un poco larga. Me he adelantado y he publicado una <a href=\"https:\/\/github.com\/couchbaselabs\/todolite-ionic2\">proyecto de muestra<\/a> a GitHub que puedes ejecutar y revisar para complementar este tutorial.<\/p>\n<p>Clona el proyecto ejecutando:<\/p>\n<pre><code>git clone https:\/\/github.com\/couchbaselabs\/todolite-ionic2<\/code><\/pre>\n<p>Con el proyecto descargado, necesitamos restaurar las dependencias del proyecto, plugins y plataformas. Ejecute lo siguiente para restaurar esas dependencias:<\/p>\n<pre><code>npm install\r\nrestauraci\u00f3n del estado de ionic<\/code><\/pre>\n<p>Ahora puedes proceder a ejecutar la aplicaci\u00f3n en tu dispositivo o simulador. Eso s\u00ed, no olvides ejecutar Couchbase Sync Gateway y actualizar el <code>sincronizar<\/code> para reflejar el de su configuraci\u00f3n remota.<\/p>\n<h2 id=\"conclusion\">Conclusi\u00f3n<\/h2>\n<p>Acabas de ver c\u00f3mo crear una aplicaci\u00f3n m\u00f3vil h\u00edbrida multiplataforma iOS y Android con <a href=\"https:\/\/www.ionicframework.com\">I\u00f3nico 2<\/a> que utiliza Couchbase Mobile. Este es un paso adelante y revisita de mi <a href=\"https:\/\/www.couchbase.com\/blog\/es\/using-couchbase-in-your-ionic-framework-application-part-1\/\">art\u00edculo anterior<\/a> que demostr\u00f3 Ionic Framework 1.0 y Couchbase Mobile.<\/p>","protected":false},"excerpt":{"rendered":"<p>Last year I wrote about using Couchbase Mobile in an Ionic Framework mobile application. Back then we were using Ionic Framework 1.0 and AngularJS 1.0. Technology has changed over the months and we&#8217;ve moved from what seems like ancient frameworks [&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":[1815,1810,9327],"tags":[1535,1773,1534,1543],"ppma_author":[9032],"class_list":["post-2456","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-best-practices-and-tutorials","category-couchbase-mobile","category-javascript","tag-apache-cordova","tag-ionic-2","tag-ionic-framework","tag-javascript"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.8 (Yoast SEO v25.8) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Couchbase Mobile in an Android and iOS Ionic 2 applicat<\/title>\n<meta name=\"description\" content=\"This blog covers how to create a cross-platform iOS and Android hybrid mobile application with Ionic 2 that uses Couchbase Mobile.\" \/>\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\/es\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/\" \/>\n<meta property=\"og:locale\" content=\"es_MX\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Data Synchronization with Couchbase in Ionic 2 Hybrid Mobile Apps\" \/>\n<meta property=\"og:description\" content=\"This blog covers how to create a cross-platform iOS and Android hybrid mobile application with Ionic 2 that uses Couchbase Mobile.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/es\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/\" \/>\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=\"2016-12-15T15:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T03:15:37+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=\"11 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/\"},\"author\":{\"name\":\"Nic Raboy, Developer Advocate, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1\"},\"headline\":\"Data Synchronization with Couchbase in Ionic 2 Hybrid Mobile Apps\",\"datePublished\":\"2016-12-15T15:00:00+00:00\",\"dateModified\":\"2025-06-14T03:15:37+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/\"},\"wordCount\":1856,\"commentCount\":17,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"keywords\":[\"apache cordova\",\"ionic 2\",\"ionic framework\",\"javascript\"],\"articleSection\":[\"Best Practices and Tutorials\",\"Couchbase Mobile\",\"JavaScript\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/\",\"name\":\"Couchbase Mobile in an Android and iOS Ionic 2 applicat\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2016-12-15T15:00:00+00:00\",\"dateModified\":\"2025-06-14T03:15:37+00:00\",\"description\":\"This blog covers how to create a cross-platform iOS and Android hybrid mobile application with Ionic 2 that uses Couchbase Mobile.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/#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\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Data Synchronization with Couchbase in Ionic 2 Hybrid Mobile Apps\"}]},{\"@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\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@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\":\"es\",\"@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\/es\/author\/nic-raboy-2\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Couchbase Mobile in an Android and iOS Ionic 2 applicat","description":"This blog covers how to create a cross-platform iOS and Android hybrid mobile application with Ionic 2 that uses Couchbase Mobile.","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\/es\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/","og_locale":"es_MX","og_type":"article","og_title":"Data Synchronization with Couchbase in Ionic 2 Hybrid Mobile Apps","og_description":"This blog covers how to create a cross-platform iOS and Android hybrid mobile application with Ionic 2 that uses Couchbase Mobile.","og_url":"https:\/\/www.couchbase.com\/blog\/es\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/","og_site_name":"The Couchbase Blog","article_author":"https:\/\/www.facebook.com\/thepolyglotdeveloper","article_published_time":"2016-12-15T15:00:00+00:00","article_modified_time":"2025-06-14T03:15:37+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":"11 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/"},"author":{"name":"Nic Raboy, Developer Advocate, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1"},"headline":"Data Synchronization with Couchbase in Ionic 2 Hybrid Mobile Apps","datePublished":"2016-12-15T15:00:00+00:00","dateModified":"2025-06-14T03:15:37+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/"},"wordCount":1856,"commentCount":17,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","keywords":["apache cordova","ionic 2","ionic framework","javascript"],"articleSection":["Best Practices and Tutorials","Couchbase Mobile","JavaScript"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/","url":"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/","name":"Couchbase Mobile in an Android and iOS Ionic 2 applicat","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2016-12-15T15:00:00+00:00","dateModified":"2025-06-14T03:15:37+00:00","description":"This blog covers how to create a cross-platform iOS and Android hybrid mobile application with Ionic 2 that uses Couchbase Mobile.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/#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\/data-synchronization-with-couchbase-in-ionic-2-hybrid-mobile-apps\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Data Synchronization with Couchbase in Ionic 2 Hybrid Mobile Apps"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"El blog de Couchbase","description":"Couchbase, la base de datos 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":"es"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"El blog de Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"es","@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 del Desarrollador, Couchbase","image":{"@type":"ImageObject","inLanguage":"es","@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 es un defensor de las tecnolog\u00edas modernas de desarrollo web y m\u00f3vil. Tiene experiencia en Java, JavaScript, Golang y una variedad de frameworks como Angular, NativeScript y Apache Cordova. Nic escribe sobre sus experiencias de desarrollo relacionadas con hacer el desarrollo web y m\u00f3vil m\u00e1s f\u00e1cil de entender.","sameAs":["https:\/\/www.thepolyglotdeveloper.com","https:\/\/www.facebook.com\/thepolyglotdeveloper","https:\/\/x.com\/nraboy"],"url":"https:\/\/www.couchbase.com\/blog\/es\/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 es un defensor de las tecnolog\u00edas modernas de desarrollo web y m\u00f3vil. Tiene experiencia en Java, JavaScript, Golang y una variedad de frameworks como Angular, NativeScript y Apache Cordova. Nic escribe sobre sus experiencias de desarrollo relacionadas con hacer el desarrollo web y m\u00f3vil m\u00e1s f\u00e1cil de entender."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/2456","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/users\/63"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/comments?post=2456"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/2456\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media?parent=2456"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/categories?post=2456"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/tags?post=2456"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/ppma_author?post=2456"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}