{"id":1977,"date":"2015-10-23T08:09:45","date_gmt":"2015-10-23T08:09:44","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=1977"},"modified":"2025-06-13T20:09:56","modified_gmt":"2025-06-14T03:09:56","slug":"couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/es\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/","title":{"rendered":"Couchbase Mobile 101: C\u00f3mo crear tu primera aplicaci\u00f3n [Couchbase LIVE New York]."},"content":{"rendered":"<p style=\"text-align: center\"><a href=\"https:\/\/bit.ly\/CBNYC2015\"><img decoding=\"async\" src=\"\/wp-content\/original-assets\/2015\/october\/couchbase-live-new-york-couchbase-101---how-to-build-your-first-couchbase-mobile-app\/events.cbliveny.bannerheader.lockup.png\" \/><\/a><\/p>\n<p style=\"text-align: justify\">A partir de la sesi\u00f3n 101 del <a href=\"https:\/\/bit.ly\/couchbaseNYC01\">Pista m\u00f3vil Couchbase LIVE Nueva York<\/a>en el que repasamos c\u00f3mo empezar a integrar Couchbase Lite en tus proyectos iOS y Android.  Desde el <a href=\"https:\/\/www.slideshare.net\/Couchbase\/couchbase-mobile-101-couchbase-live-new-york?\">\"Diapositivas \"Couchbase Mobile 101: C\u00f3mo crear su primera aplicaci\u00f3n m\u00f3vil<\/a>exploramos las APIs de Couchbase Mobile recorriendo la aplicaci\u00f3n de ejemplo Grocery Sync que se puede encontrar en el repositorio de Github para <a href=\"https:\/\/github.com\/couchbaselabs\/Grocery-Sync-iOS\">iOS<\/a> y <a href=\"https:\/\/github.com\/couchbaselabs\/GrocerySync-Android\">Android<\/a>.  En este blog, recapitularemos a alto nivel las caracter\u00edsticas y APIs de Couchbase Lite que fueron presentadas en la sesi\u00f3n Couchbase 101, as\u00ed como parte del c\u00f3digo encontrado en el ejemplo Grocery Sync.  Para empezar <a href=\"https:\/\/bit.ly\/couchbase_downloads\">descargar Couchbase Lite<\/a> Enterprise Edition para la plataforma en la que est\u00e9s desarrollando y sigue el tutorial de iOS o el tutorial de Android para integrar Couchbase Lite en tus proyectos m\u00f3viles.<\/p>\n<p style=\"text-align: justify\">Despu\u00e9s de traer Couchbase Lite a tus proyectos m\u00f3viles, necesitar\u00edamos inicializar Couchbase Lite y recuperar o crear una base de datos.  A continuaci\u00f3n se presentan algunos conceptos y requisitos de Couchbase Mobile que necesitamos.<\/p>\n<p style=\"text-align: justify\"><strong>[1] Director<\/strong><\/p>\n<p style=\"text-align: justify\">En <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/1.1.0\/develop\/references\/couchbase-lite\/couchbase-lite\/manager\/index.html\">Director<\/a> es la clase de nivel superior a la que se debe hacer referencia al crear un espacio de nombres para bases de datos.  Crear una base de datos es simplemente hacer referencia a un nombre de cadena como a continuaci\u00f3n:<\/p>\n<p style=\"text-align: justify\"><strong>iOS<\/strong><\/p>\n<pre><code class=\"language-objc\">\r\n    NSError* error;\r\n    self.database = [[CBLManager sharedInstance] databaseNamed: kDatabaseName\r\n                                                         error: &amp;error];\r\n    if (!self.database) {\r\n        [self showAlert: @\"Couldn't open database\" error: error fatal: YES];\r\n        return NO;\r\n    }\r\n<\/code><\/pre>\n<p style=\"text-align: justify\"><strong>Android<\/strong><\/p>\n<pre><code class=\"language-java\">\r\nmanager = new Manager(new AndroidContext(this), Manager.DEFAULT_OPTIONS);\r\ndatabase = manager.getDatabase(DATABASE_NAME);\r\n<\/code><\/pre>\n<p style=\"text-align: justify\">Con ese c\u00f3digo en su lugar, somos capaces de recuperar los documentos que contienen JSON de la base de datos en consecuencia.  La base de datos tambi\u00e9n sirve como fuente y destino para la replicaci\u00f3n.   Cada documento tiene un nombre \u00fanico y un ID \u00fanico.  M\u00e1s all\u00e1 de eso tienen JSON como sus propiedades, donde el objeto JSON es un conjunto de propiedades de nombre donde sus valores pueden ser nombres o cadenas, n\u00fameros, matrices, diccionarios, y etc.<\/p>\n<p style=\"text-align: justify\"><strong>[2] Documentos<\/strong><\/p>\n<p style=\"text-align: justify\">En <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/1.1.0\/develop\/guides\/couchbase-lite\/native-api\/document\/index.html\">Documento<\/a> incluye un ID de documento inmutable dentro de la base de datos donde el cuerpo del documento toma la forma de un objeto anidado JSON de pares clave-valor.  Para permitir que diferentes tipos de documentos coexistan en una base de datos, la convenci\u00f3n que se utiliza com\u00fanmente es incluir una propiedad llamada \"tipo\" que luego tiene una cadena que define el tipo de sus documentos.  Se trata de una t\u00e9cnica utilizada para realizar un seguimiento de los diferentes tipos de documentos si hay m\u00e1s de un tipo en una base de datos y tambi\u00e9n ayuda con la indexaci\u00f3n.  Los documentos tambi\u00e9n contienen <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/1.1.0\/develop\/guides\/couchbase-lite\/native-api\/revision\/index.html\">revisiones<\/a> a efectos de seguimiento de historiales de cambios y conflictos, por lo que es clave para el funcionamiento de la replicaci\u00f3n.<\/p>\n<p style=\"text-align: justify\">Para insertar documentos se utiliza el bot\u00f3n '<a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/1.1.0\/develop\/references\/couchbase-lite\/couchbase-lite\/database\/database\/index.html\">crearDocumento()<\/a>devolver\u00e1 un ID de un documento que est\u00e1 en forma de UUID generado aleatoriamente.  En la aplicaci\u00f3n de ejemplo para iOS, se crea un 'NSDictionary' que corresponde a un 'NSObject' en Objective-C con las propiedades 'text', 'check' y 'created_at' definidas.  Abajo para ..<\/p>\n<p style=\"text-align: justify\"><strong>iOS<\/strong><\/p>\n<pre><code>\r\n    NSDictionary *document = @{@\"text\":       text,\r\n                               @\"check\":      @NO,\r\n                               @\"created_at\": [CBLJSON JSONObjectWithDate:\r\n                                                                   [NSDate date]]};\r\n    \/\/ Save the document:\r\n    CBLDocument* doc = [database createDocument];\r\n    NSError* error;\r\n    if (![doc putProperties: document error: &amp;error]) {\r\n        [self showErrorAlert: @\"Couldn't save new item\" forError: error];\r\n    }\r\n<\/code><\/pre>\n<p>creamos las propiedades del nuevo documento y luego guardamos el documento haciendo referencia a la base de datos para el m\u00e9todo 'createDocument()'.  El 'JSONObjectWithDate' es una funci\u00f3n de utilidad para tomar un objeto de fecha Cocao y lo convierte en un formato de cadena ISO8601 ya que las fechas no se pueden almacenar como objetos nativos en JSON.<\/p>\n<p>Para Android, la clase 'SimpleDateFormat' est\u00e1 creando el 'currentTimeString' para el objeto donde el ID del documento se construye mediante la combinaci\u00f3n del 'currentTime' de la clase 'Calendar' y el UUID del m\u00e9todo 'randomUUID()'.  Haciendo referencia a la \"base de datos\" creada a partir de la clase Manager, se crea un documento llamando al mismo m\u00e9todo \"createDocument()\" que en iOS.  En Android, los emparejamientos Clave-Valor se asemejan a una estructura de objetos HashMap, por lo que creamos un Mapa que es el equivalente Java del objeto JSON en la variable 'properties'.  Las mismas tres propiedades se insertan en el mapa Java por el m\u00e9todo 'put()' y luego para persistir en disco, el objeto Map se pasa al m\u00e9todo 'putProperties()'.  Esto se ilustra a continuaci\u00f3n:<\/p>\n<p><strong>Android<\/strong><\/p>\n<pre><code>\r\n    SimpleDateFormat dateFormatter = new SimpleDateFormat(\r\n                                                   \"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'\");\r\n    UUID uuid = UUID.randomUUID();\r\n    Calendar calendar = GregorianCalendar.getInstance();\r\n    long currentTime = calendar.getTimeInMillis();\r\n    String currentTimeString = dateFormatter.format(calendar.getTime());\r\n    String id = currentTime + \"-\" + uuid.toString();\r\n\r\n    Document document = database.createDocument();\r\n    Map(String, Object) properties = new HashMap(String, Object)();\r\n    properties.put(\"_id\", id);\r\n    properties.put(\"text\", text);\r\n    properties.put(\"check\", Boolean.FALSE);\r\n    properties.put(\"created_at\", currentTimeString);\r\n\r\n    document.putProperties(properties);\r\n<\/code><\/pre>\n<p style=\"text-align: justify\"><strong>[3] Archivos adjuntos<\/strong><\/p>\n<p style=\"text-align: justify\">En <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/current\/develop\/guides\/couchbase-lite\/native-api\/attachment\/index.html\">Adjunto<\/a> aunque no se utiliza en el ejemplo, permite a los documentos adjuntar cualquier blob binario de tama\u00f1o arbitrario y, por lo tanto, es una t\u00e9cnica de optimizaci\u00f3n para la replicaci\u00f3n en la que las actualizaciones de los documentos son independientes de las actualizaciones de los adjuntos, ya que se almacenan por separado del cuerpo JSON.  Por ejemplo, esto puede ser un caso de uso para cuando los metadatos, documento JSON, se cambia en un archivo adjunto asociado y por lo tanto si un documento se actualiza sin cambios en un archivo adjunto, a continuaci\u00f3n, el replicador puede omitir el env\u00edo del archivo adjunto.<\/p>\n<p style=\"text-align: justify\"><strong>[4] Puntos de vista<\/strong><\/p>\n<p style=\"text-align: justify\">En <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/1.1.0\/develop\/guides\/couchbase-lite\/native-api\/view\/index.html\">Ver<\/a> permite a las aplicaciones crear y mantener \u00edndices secundarios utilizando la t\u00e9cnica map &amp; reduce.  Empezamos con un documento JSON y la funci\u00f3n de mapa es la funci\u00f3n que escribes que toma ese documento como entrada y produce un conjunto de pares clave-valor.  La salida de esa funci\u00f3n de mapa que se ejecuta a trav\u00e9s de todos los documentos en la base de datos genera un \u00edndice.  En la aplicaci\u00f3n de ejemplo Grocery Sync, estamos definiendo una Vista con una funci\u00f3n de mapa que indexa los elementos pendientes por fecha de creaci\u00f3n.  Crear una Vista para..<\/p>\n<p style=\"text-align: justify\"><strong>iOS<\/strong><\/p>\n<pre><code class=\"language-objective-c\">\r\n[[theDatabase viewNamed: @\"byDate\"] setMapBlock: MAPBLOCK({\r\n        id date = doc[@\"created_at\"];\r\n        if (date)\r\n            emit(date, nil);\r\n    }) version: @\"1.1\"];\r\n<\/code><\/pre>\n<p>Para iOS, primero estamos creando una 'Vista' en la base de datos.  La base de datos es tambi\u00e9n un contenedor o espacio de nombres para las 'Vistas', por lo que decimos 'viewNamed: @\"byDate\"' donde si la View no existe la crearemos y si existe la devolveremos.  El resto del bloque de c\u00f3digo es para establecer su Map Block.  Esta es una vista MapReduce, lo que significa que tiene una funci\u00f3n Map.  Obtenemos la fecha del documento mirando la propiedad 'created_at'.  Y si el documento tiene una, la emitimos como clave. En la aplicaci\u00f3n Grocery Sync, no se emite nada para el valor, porque en realidad va a volver a agarrar el propio documento para obtener el resto de los datos.  La cadena de versi\u00f3n, '@\"1.1\u2033' al final se utiliza para comunicarse con la base de datos sobre si su funci\u00f3n de mapa ha cambiado o no.  Dado que la base de datos no puede decir cuando la funci\u00f3n de mapa ha cambiado de una ejecuci\u00f3n a la siguiente; una t\u00e9cnica es aumentar la cadena de versi\u00f3n para decirle a la base de datos que tire el \u00edndice actual y lo reconstruya.<\/p>\n<p style=\"text-align: justify\"><strong>Android<\/strong><\/p>\n<pre><code class=\"language-objc\">\r\n    com.couchbase.lite.View viewItemsByDate = \r\n            database.getView(String.format(\"%s\/%s\", designDocName, byDateViewName));\r\n    viewItemsByDate.setMap(new Mapper() {\r\n        @Override\r\n        public void map(Map(String, Object) document, Emitter emitter) {\r\n            Object createdAt = document.get(\"created_at\");\r\n            if (createdAt != null) {\r\n                emitter.emit(createdAt.toString(), null);\r\n            }\r\n        }\r\n    }, \"1.0\");\r\n\r\n<\/code><\/pre>\n<p>Esta es la versi\u00f3n Java-Android en la que, de forma similar a iOS, llamamos a 'database.getView()' y luego creamos la 'funci\u00f3n map' utilizando alguna sintaxis de clase interna que en Java existe como un objeto 'Mapper()'.  Los \u00edndices son capaces de ser actualizados en la demanda y la informaci\u00f3n \u00fatil son capaces de ser extra\u00eddos del documento que desea indexar donde entonces la clave-valor puede ser emitido.  Cada vez que algo cambia, la funci\u00f3n map se alimenta de ese documento. La funci\u00f3n map llama a una funci\u00f3n llamada 'emit()' que toma la 'clave y el valor' como par\u00e1metros.<\/p>\n<p>Lo que la aplicaci\u00f3n Grocery Sync est\u00e1 haciendo aqu\u00ed es generar el \u00edndice de todos los elementos pendientes que est\u00e1n abreviados por 'clave' y como la clave es la marca de tiempo, los elementos estar\u00e1n ordenados cronol\u00f3gicamente donde las cadenas de valor son los nombres de los elementos pendientes.  El \u00edndice tambi\u00e9n recuerda el ID del documento que emiti\u00f3 ese par clave-valor.  De este modo, cuando realices una consulta y tengas una fila en ella, podr\u00e1s utilizarla para volver al documento y recuperar toda la fila de la base de datos si lo deseas.  La idea aqu\u00ed es que una vez que tengas este \u00edndice, lo consultes. La consulta se hace diciendo: \"Quiero todas las entradas del \u00edndice con una clave en particular, o un conjunto de claves, o un rango de claves\".<\/p>\n<p style=\"text-align: justify\"><strong>[5] Consultas<\/strong><\/p>\n<p style=\"text-align: justify\">Las consultas pueden entonces buscar un rango de filas desde una vista, y utilizar las claves y valores de las filas directamente u obtener los documentos de los que provienen a partir del ID del documento.  En el c\u00f3digo siguiente, estamos manejando la tabla desde una consulta de vista mediante la creaci\u00f3n de una consulta que se ordena por fecha descendente donde los elementos m\u00e1s recientes se muestran primero.<\/p>\n<p style=\"text-align: justify\"><strong>iOS<\/strong><\/p>\n<pre><code class=\"language-objc\">\r\n    CBLLiveQuery* query = [[[database viewNamed:@\"byDate\"] query] asLiveQuery];\r\n    query.descending = YES;\r\n\r\n    \/\/ Plug the query into the CBLUITableSource, which uses it to drive the table.\r\n    \/\/ (The CBLUITableSource uses KVO to observe the query's .rows property.)\r\n    self.dataSource.query = query;\r\n    self.dataSource.labelProperty = @\"text\";\r\n<\/code><\/pre>\n<p>Con los art\u00edculos en el \u00edndice, queremos usar ese \u00edndice para manejar la vista de tabla que es la UI principal de Grocery Sync.  En iOS, generamos una consulta que es 'viewNamed: @\"byDate\"' y llamamos a query que crea la consulta sobre ella.  Luego vemos 'LiveQuery' donde es un subconjunto especial de consulta que realmente rastrear\u00e1 la Vista en el tiempo.  Establecemos la propiedad \"descendente\" en la consulta a \"s\u00ed\", ya que queremos obtener las filas en orden descendente de las fechas en tener los elementos m\u00e1s recientes creados en la parte superior.  Por \u00faltimo, con el c\u00f3digo espec\u00edfico de iOS, le decimos al 'dataSource' acerca de la consulta e indicamos qu\u00e9 propiedad mostrar como etiqueta en la vista de tabla.<\/p>\n<p style=\"text-align: justify\"><strong>Android<\/strong><\/p>\n<pre><code>\r\n    liveQuery = view.createQuery().toLiveQuery();\r\n\r\n    liveQuery.addChangeListener(new LiveQuery.ChangeListener() {\r\n        public void changed(final LiveQuery.ChangeEvent event) {\r\n            runOnUiThread(new Runnable() {\r\n                public void run() {\r\n                    grocerySyncArrayAdapter.clear();\r\n                    for (Iterator(QueryRow) it = event.getRows(); it.hasNext();) {\r\n                        grocerySyncArrayAdapter.add(it.next());\r\n                    }\r\n                    grocerySyncArrayAdapter.notifyDataSetChanged();\r\n<\/code><\/pre>\n<p style=\"text-align: justify\">Del mismo modo, la versi\u00f3n Java-Android se inicia de la misma manera donde se crea una consulta haciendo que la vista llame a 'toLiveQuery()' sobre ella para generar el 'liveQuery'.  Y luego se ejecuta 'addChangeListener()' en esa liveQuery, seguido del m\u00e9todo 'changed()' que se llama para las actualizaciones de la Query, que es cada vez que cambia el resultado de esa Query.  Y la salida para cuando se ejecuta la consulta es un array de 'QueryRows' donde cada QueryRow es un objeto y tiene propiedades como Key y Value y DocumentID pero tambi\u00e9n una propiedad document que cargar\u00e1 el documento de vuelta de la base de datos.  Est\u00e1 pasando por un 'Iterator()' para obtener todas las filas de la consulta y a\u00f1adirlas al 'grocerySyncArrayAdapter' que es una clase personalizada que tiene para almacenar el conjunto de datos.<br \/>\n<strong>[6] LiveQuery<\/strong><\/p>\n<p style=\"text-align: justify\">Podemos pensar en LiveQuery como una envoltura alrededor de la consulta que escucha las notificaciones de cambio de la base de datos.  As\u00ed, cuando la base de datos cambie, el LiveQuery lanzar\u00e1 de nuevo la consulta, reejecut\u00e1ndola en segundo plano de forma as\u00edncrona.  Y entonces comparar\u00e1 los resultados de la consulta con los resultados anteriores que ya ten\u00eda.  Si los resultados han cambiado, el LiveQuery se\u00f1alar\u00e1 sus propios eventos de notificaci\u00f3n que la aplicaci\u00f3n puede manejar en consecuencia, como redibujar la interfaz de usuario basada en esa nueva consulta.  A continuaci\u00f3n, el c\u00f3digo ilustra c\u00f3mo mostrar las celdas de la tabla para..<\/p>\n<p style=\"text-align: justify\"><strong>iOS<\/strong><\/p>\n<pre><code>\r\n- (void)couchTableSource:(CBLUITableSource*)source\r\n              willUseCell:(UITableViewCell*)cell\r\n                   forRow:(CBLQueryRow*)row\r\n{\r\n    \/\/ Set the cell background and font:\r\n    \u2026\u2026\u2026\r\n    \r\n    \/\/ Configure the cell contents. Map function (above) copies the doc properties\r\n    \/\/ into its value, so we can read them without having to load the document.\r\n    NSDictionary* rowValue = row.value;\r\n    BOOL checked = [rowValue[@\"check\"] boolValue];\r\n    if (checked) {\r\n        cell.textLabel.textColor = [UIColor grayColor];\r\n        cell.imageView.image = [UIImage imageNamed:@\"checked\"];\r\n    } else {\r\n        cell.textLabel.textColor = [UIColor blackColor];\r\n        cell.imageView.image = [UIImage imageNamed: @\"unchecked\"];\r\n    }\r\n    \/\/ cell.textLabel.text is already set, thanks to setting up labelProperty\r\n<\/code><\/pre>\n<p style=\"text-align: justify\">Para la aplicaci\u00f3n de ejemplo aqu\u00ed, el 'CBLUITableSource' de Couchbase Lite actuar\u00e1 como intermediario entre el LiveQuery y el UITableView, recibiendo notificaciones de cambios y por tanto manejando la tabla basada en un Query.  Tambi\u00e9n act\u00faa como objeto fuente de datos para la tableView, lo que significa que es el objeto al que la tableView va a pedir que le proporcione todos los datos de las filas.  Tu objeto 'controlador' se convierte entonces en el delegado del UITableView donde recibir\u00e1 notificaciones del TableView sobre cuando el usuario pulse en una de las filas.<\/p>\n<p style=\"text-align: justify\"><strong>Android<\/strong><\/p>\n<pre><code>\r\npublic View getView(int position, View itemView, ViewGroup parent) {\r\n \/\/...\r\n TextView label = ((ViewHolder)itemView.getTag()).label;\r\n QueryRow row = getItem(position);\r\n SavedRevision currentRevision = row.getDocument().getCurrentRevision();\r\n \/\/ Check box\r\n Object check = (Object) currentRevision.getProperty(\"check\");\r\n boolean isGroceryItemChecked = false;\r\n if (check != null &amp;&amp; check instanceof Boolean)\r\n     isGroceryItemChecked = ((Boolean)check).booleanValue();\r\n \/\/ Text\r\n String groceryItemText = (String) currentRevision.getProperty(\"text\");\r\n label.setText(groceryItemText);\r\n<\/code><\/pre>\n<p style=\"text-align: justify\">Aqu\u00ed est\u00e1 el equivalente de Android en la clase Grocery Sync Adapter.  Obtiene la 'QueryRow' llamando a 'getItem()' bas\u00e1ndose en el n\u00famero de fila de la tabla.  A continuaci\u00f3n, obtiene el documento de la fila de consulta y obtiene su revisi\u00f3n actual. Luego utiliza las propiedades check y text para rellenar los UI Controls en la fila.<\/p>\n<p style=\"text-align: justify\">Por \u00faltimo, para la aplicaci\u00f3n de ejemplo Grocery Sync, necesitamos responder a una pulsaci\u00f3n en una fila de la tabla, como por ejemplo cambiar la marca de verificaci\u00f3n.  A continuaci\u00f3n se ilustra c\u00f3mo se hace esto haciendo referencia a la QueryRow en un \u00edndice particular y recuperar el documento fuera de \u00e9l.<\/p>\n<p style=\"text-align: justify\"><strong>iOS<\/strong><\/p>\n<pre><code>\r\n- (void)tableView:(UITableView *)tableView \r\n         didSelectRowAtIndexPath:(NSIndexPath *)indexPath\r\n{\r\n    \/\/ Ask CBLUITableSource for the corresponding query row, and get its document:\r\n    CBLQueryRow *row = [self.dataSource rowAtIndex:indexPath.row];\r\n    CBLDocument *doc = row.document;\r\n\r\n    \/\/ Toggle the document's 'checked' property:\r\n    NSMutableDictionary *docContent = [doc.properties mutableCopy];\r\n    BOOL wasChecked = [docContent[@\"check\"] boolValue];\r\n    docContent[@\"check\"] = @(!wasChecked);\r\n\r\n    \/\/ Save changes:\r\n    NSError* error;\r\n    if (![doc.currentRevision putProperties: docContent error: &amp;error]) {\r\n        [self showErrorAlert: @\"Failed to update item\" forError: error];\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>Esta es una llamada a un m\u00e9todo sobre el propio UITableView en su delegado.  Diciendo que una fila fue seleccionada lo que significa 'TAPPED' As\u00ed que va a ir a la fuente de datos. Que es el objeto UI Table Source, y le preguntar\u00e1 por la fila de consulta en ese \u00edndice, y obtendr\u00e1 el documento. As\u00ed que ahora b\u00e1sicamente est\u00e1 haciendo un ciclo de Lectura, Escritura, Modificaci\u00f3n en ese documento. Donde obtiene las propiedades... hace una copia mutable de las propiedades donde ahora tenemos un diccionario mutable donde podemos actualizar.  Lee la propiedad verificada como un booleano, y la escribe de nuevo como lo contrario. As\u00ed que esto es invertir el valor booleano de la propiedad comprobada. Luego llama a putProperties al final para guardar ese valor de nuevo.<\/p>\n<p style=\"text-align: justify\"><strong>Android<\/strong><\/p>\n<pre><code>\r\npublic void onItemClick(AdapterView(?) adapterView, View view, int position, long id) \r\n{\r\n    QueryRow row = (QueryRow) adapterView.getItemAtPosition(position);\r\n    Document document = row.getDocument();\r\n    Map(String, Object) newProperties = \r\n                              new HashMap(String, Object)(document.getProperties());\r\n\r\n    boolean checked = ((Boolean) newProperties.get(\"check\")).booleanValue();\r\n    newProperties.put(\"check\", !checked);\r\n\r\n    try {\r\n        document.putProperties(newProperties);\r\n        grocerySyncArrayAdapter.notifyDataSetChanged();\r\n    } catch (Exception e) {\r\n<\/code><\/pre>\n<p>Pasando ahora a la versi\u00f3n de Android, tenemos un 'onItemClick()' que es llamado por la GUI de Android.  Se va a obtener su QueryRow en esa posici\u00f3n, obtener el documento, obtener las propiedades y, a continuaci\u00f3n, poner las propiedades.  En las APIs de Java es idiom\u00e1tico usar excepciones donde no lo es en Objective C, as\u00ed que esto tiene un try-catch envuelto alrededor del manejador al guardar el documento.   Si en la Ventana de Tiempo algo m\u00e1s modificara el documento, probablemente el replicador, entonces esto arrojar\u00eda un error. Obtendr\u00edas un error de conflicto.<\/p>\n<p style=\"text-align: justify\">A continuaci\u00f3n nos adentraremos en la clase Couchbase Lite Replicator y en la clase <a href=\"https:\/\/www.couchbase.com\/blog\/es\/developers\/mobile\/\">Portal para desarrolladores de Couchbase Mobile<\/a> es un buen recurso para empezar.<\/p>\n<p style=\"text-align: center\"><a href=\"https:\/\/bit.ly\/CBNYC2015\"><img decoding=\"async\" src=\"\/wp-content\/original-assets\/2015\/october\/couchbase-live-new-york-couchbase-101---how-to-build-your-first-couchbase-mobile-app\/events.cbliveny.blog.banner.jpg\" \/><\/a><\/p>\n<p>\u00a0A partir de ah\u00ed nos sumergiremos en <a href=\"https:\/\/bit.ly\/sync_gateway\">Pasarela de sincronizaci\u00f3n Couchbase<\/a> en nuestra sesi\u00f3n 102, en la que hablar\u00e9 de <a href=\"https:\/\/bit.ly\/CBNYC2015_102\">\"C\u00f3mo a\u00f1adir Secure Sync a tu aplicaci\u00f3n m\u00f3vil\".<\/a>\u00a0 Completaremos el d\u00eda con c\u00f3mo activar la funci\u00f3n Peer-to-Peer de Couchbase Mobile en la sesi\u00f3n 103 con <a href=\"https:\/\/twitter.com\/agonyou\">Austin Gonyou<\/a>donde se pueden crear experiencias sociales \u00fanicas dentro de la aplicaci\u00f3n mediante \"Building a Peer-to-Peer App with Couchbase Mobile\".<\/p>","protected":false},"excerpt":{"rendered":"<p>From the 101 session in the Couchbase LIVE New York mobile track, we went over on how to get started with integrating Couchbase Lite to your iOS and Android projects.\u00a0 From the &#8220;Couchbase Mobile 101: How to Build Your First [&hellip;]<\/p>","protected":false},"author":30,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[7667,1810,9410],"tags":[],"ppma_author":[8983],"class_list":["post-1977","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-couchbase-lite","category-couchbase-mobile","category-objective-c"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Couchbase Mobile 101 - How to Build Your First App<\/title>\n<meta name=\"description\" content=\"Check the Couchbase Lite features and APIs that were presented at the Couchbase 101 session as well as some of the code found in the Grocery Sync sample.\" \/>\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\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/\" \/>\n<meta property=\"og:locale\" content=\"es_MX\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Couchbase Mobile 101: How to Build Your First App [Couchbase LIVE New York]\" \/>\n<meta property=\"og:description\" content=\"Check the Couchbase Lite features and APIs that were presented at the Couchbase 101 session as well as some of the code found in the Grocery Sync sample.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/es\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2015-10-23T08:09:44+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T03:09:56+00:00\" \/>\n<meta name=\"author\" content=\"William Hoang, Mobile Developer Advocate, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"William Hoang, Mobile Developer Advocate, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/\"},\"author\":{\"name\":\"William Hoang, Mobile Developer Advocate, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/425717456c198fdf9aaa5d7a6d42ad32\"},\"headline\":\"Couchbase Mobile 101: How to Build Your First App [Couchbase LIVE New York]\",\"datePublished\":\"2015-10-23T08:09:44+00:00\",\"dateModified\":\"2025-06-14T03:09:56+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/\"},\"wordCount\":2141,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"articleSection\":[\"Couchbase Lite\",\"Couchbase Mobile\",\"Objective-C\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/\",\"name\":\"Couchbase Mobile 101 - How to Build Your First App\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2015-10-23T08:09:44+00:00\",\"dateModified\":\"2025-06-14T03:09:56+00:00\",\"description\":\"Check the Couchbase Lite features and APIs that were presented at the Couchbase 101 session as well as some of the code found in the Grocery Sync sample.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#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\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Couchbase Mobile 101: How to Build Your First App [Couchbase LIVE New York]\"}]},{\"@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\/425717456c198fdf9aaa5d7a6d42ad32\",\"name\":\"William Hoang, Mobile Developer Advocate, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/650445f1ea30314c4f3555dd680154f5\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/b912c9a97568a859697ee195432d0bd7cc3ed67d720ae2e6588b67313fa49e08?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/b912c9a97568a859697ee195432d0bd7cc3ed67d720ae2e6588b67313fa49e08?s=96&d=mm&r=g\",\"caption\":\"William Hoang, Mobile Developer Advocate, Couchbase\"},\"description\":\"William was a Developer Advocate on the Mobile Engineering\/Developer Experience team at Couchbase. His love for coffee and code has transcended him into the world of mobile while appreciating the offline in-person experiences. Prior, William worked on the Developer Relations team over at Twitter, BlackBerry, and Microsoft while also having been a Software Embedded GPS engineer at Research In Motion. William graduated from McGill University in Electrical Software Engineering\",\"url\":\"https:\/\/www.couchbase.com\/blog\/es\/author\/william-hoang\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Couchbase Mobile 101 - How to Build Your First App","description":"Echa un vistazo a las caracter\u00edsticas y APIs de Couchbase Lite que se presentaron en la sesi\u00f3n Couchbase 101, as\u00ed como parte del c\u00f3digo que se encuentra en el ejemplo de Grocery Sync.","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\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/","og_locale":"es_MX","og_type":"article","og_title":"Couchbase Mobile 101: How to Build Your First App [Couchbase LIVE New York]","og_description":"Check the Couchbase Lite features and APIs that were presented at the Couchbase 101 session as well as some of the code found in the Grocery Sync sample.","og_url":"https:\/\/www.couchbase.com\/blog\/es\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/","og_site_name":"The Couchbase Blog","article_published_time":"2015-10-23T08:09:44+00:00","article_modified_time":"2025-06-14T03:09:56+00:00","author":"William Hoang, Mobile Developer Advocate, Couchbase","twitter_card":"summary_large_image","twitter_misc":{"Written by":"William Hoang, Mobile Developer Advocate, Couchbase","Est. reading time":"10 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/"},"author":{"name":"William Hoang, Mobile Developer Advocate, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/425717456c198fdf9aaa5d7a6d42ad32"},"headline":"Couchbase Mobile 101: How to Build Your First App [Couchbase LIVE New York]","datePublished":"2015-10-23T08:09:44+00:00","dateModified":"2025-06-14T03:09:56+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/"},"wordCount":2141,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","articleSection":["Couchbase Lite","Couchbase Mobile","Objective-C"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/","url":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/","name":"Couchbase Mobile 101 - How to Build Your First App","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2015-10-23T08:09:44+00:00","dateModified":"2025-06-14T03:09:56+00:00","description":"Echa un vistazo a las caracter\u00edsticas y APIs de Couchbase Lite que se presentaron en la sesi\u00f3n Couchbase 101, as\u00ed como parte del c\u00f3digo que se encuentra en el ejemplo de Grocery Sync.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#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\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Couchbase Mobile 101: How to Build Your First App [Couchbase LIVE New York]"}]},{"@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\/425717456c198fdf9aaa5d7a6d42ad32","name":"William Hoang, Defensor del Desarrollador M\u00f3vil, Couchbase","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/650445f1ea30314c4f3555dd680154f5","url":"https:\/\/secure.gravatar.com\/avatar\/b912c9a97568a859697ee195432d0bd7cc3ed67d720ae2e6588b67313fa49e08?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/b912c9a97568a859697ee195432d0bd7cc3ed67d720ae2e6588b67313fa49e08?s=96&d=mm&r=g","caption":"William Hoang, Mobile Developer Advocate, Couchbase"},"description":"William fue Developer Advocate en el equipo de Mobile Engineering\/Developer Experience de Couchbase. Su amor por el caf\u00e9 y el c\u00f3digo le ha trascendido al mundo de los m\u00f3viles, al tiempo que aprecia las experiencias presenciales fuera de l\u00ednea. Anteriormente, William trabaj\u00f3 en el equipo de Relaciones con Desarrolladores en Twitter, BlackBerry y Microsoft, adem\u00e1s de haber sido ingeniero de Software Embedded GPS en Research In Motion. William se licenci\u00f3 en Ingenier\u00eda El\u00e9ctrica de Software por la Universidad McGill.","url":"https:\/\/www.couchbase.com\/blog\/es\/author\/william-hoang\/"}]}},"authors":[{"term_id":8983,"user_id":30,"is_guest":0,"slug":"william-hoang","display_name":"William Hoang, Mobile Developer Advocate, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/b912c9a97568a859697ee195432d0bd7cc3ed67d720ae2e6588b67313fa49e08?s=96&d=mm&r=g","author_category":"","last_name":"Hoang","first_name":"William","job_title":"","user_url":"","description":"William fue Developer Advocate en el equipo de Mobile Engineering\/Developer Experience de Couchbase. Su amor por el caf\u00e9 y el c\u00f3digo le ha trascendido al mundo de los m\u00f3viles, al tiempo que aprecia las experiencias presenciales fuera de l\u00ednea. Anteriormente, William trabaj\u00f3 en el equipo de Relaciones con Desarrolladores en Twitter, BlackBerry y Microsoft, adem\u00e1s de haber sido ingeniero de Software Embedded GPS en Research In Motion. William se licenci\u00f3 en Ingenier\u00eda El\u00e9ctrica de Software por la Universidad McGill."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/1977","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\/30"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/comments?post=1977"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/1977\/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=1977"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/categories?post=1977"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/tags?post=1977"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/ppma_author?post=1977"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}