{"id":338,"date":"2015-10-23T08:09:45","date_gmt":"2015-10-23T08:09:44","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/"},"modified":"2015-10-23T08:09:45","modified_gmt":"2015-10-23T08:09:44","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: How to Build Your First App [Couchbase LIVE New York]"},"content":{"rendered":"\n<p><a href=\"https:\/\/bit.ly\/CBNYC2015\"><img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/wp-content\/uploads\/sites\/5\/2026\/05\/events.cbliveny.bannerheader.lockup.png\"><\/a><\/p>\n\n\n\n<p>From the 101 session in the <a href=\"https:\/\/bit.ly\/couchbaseNYC01\">Couchbase LIVE New York mobile track<\/a>, we went over on how to get started with integrating Couchbase Lite to your iOS and Android projects.\u00a0 From the <a href=\"https:\/\/www.slideshare.net\/Couchbase\/couchbase-mobile-101-couchbase-live-new-york?\">&#8220;Couchbase Mobile 101: How to Build Your First Mobile App&#8221; slides<\/a>, we explored the APIs of Couchbase Mobile by walking over the Grocery Sync sample application which can be found on the Github repo for <a href=\"https:\/\/github.com\/couchbaselabs\/Grocery-Sync-iOS\">iOS<\/a> and <a href=\"https:\/\/github.com\/couchbaselabs\/GrocerySync-Android\">Android<\/a>.\u00a0 In this blog, we will recap at a high level 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.\u00a0 To start, you would <a href=\"https:\/\/bit.ly\/couchbase_downloads\">download Couchbase Lite<\/a> Enterprise Edition for the platform you are developing on and follow either the iOS tutorial or Android tutorial to integrate Couchbase Lite to your mobile projects.<\/p>\n\n\n\n<p>After bringing in Couchbase Lite to your mobile projects, we would need to initialize Couchbase Lite and retrieve or create a database.\u00a0 Below are some Couchbase Mobile concepts and requirements we need.<\/p>\n\n\n\n<p><strong>[1] Manager<\/strong><\/p>\n\n\n\n<p>The <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/1.1.0\/develop\/references\/couchbase-lite\/couchbase-lite\/manager\/index.html\">Manager<\/a> is the top level class to reference in creating a namespace for databases.\u00a0 Creating a database is simply referencing a string name like below:<\/p>\n\n\n\n<p><strong>iOS<\/strong><\/p>\n\n\n<p>[crayon lang=&#8221;objc&#8221;]<br \/>\n    NSError* error;<br \/>\n    self.database = [[CBLManager sharedInstance] databaseNamed: kDatabaseName<br \/>\n                                                         error: &#038;error];<br \/>\n    if (!self.database) {<br \/>\n        [self showAlert: @&#8221;Couldn&#8217;t open database&#8221; error: error fatal: YES];<br \/>\n        return NO;<br \/>\n    }<br \/>\n[\/crayon]<\/p>\n\n\n\n<p><strong>Android<\/strong><\/p>\n\n\n<p>[crayon lang=&#8221;java&#8221;]<br \/>\nmanager = new Manager(new AndroidContext(this), Manager.DEFAULT_OPTIONS);<br \/>\ndatabase = manager.getDatabase(DATABASE_NAME);<br \/>\n[\/crayon]<\/p>\n\n\n\n<p>With that code in place, we are able to retrieve the documents containing JSON out of the database accordingly.\u00a0 The database also serves as the source and target for replication. \u00a0 The documents each have their respective unique name and unique ID.\u00a0 Beyond that they have JSON as their properties, where the JSON object is a set of name properties where its values may be names or strings, numbers, arrays, dictionaries, and etc.<\/p>\n\n\n\n<p><strong>[2] Documents<\/strong><\/p>\n\n\n\n<p>The <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/1.1.0\/develop\/guides\/couchbase-lite\/native-api\/document\/index.html\">Document<\/a> includes an immutable document ID within the database where the document&#8217;s body takes the form of a JSON nested object of key-value pairs.\u00a0 To allow for different types of documents to co-exist in a database, the convention that is commonly used is to include a property called &#8216;type&#8217; which then has a String that defines the type of your documents.\u00a0 This is a technique used to keep track of different document types if there are more than one type in a database and also help with indexing.\u00a0 Documents also contain <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/1.1.0\/develop\/guides\/couchbase-lite\/native-api\/revision\/index.html\">revisions<\/a> for the purposes of tracking change histories and conflicts therefore it is key to how replication works.<\/p>\n\n\n\n<p>To insert documents the &#8216;<a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/1.1.0\/develop\/references\/couchbase-lite\/couchbase-lite\/database\/database\/index.html\">createDocument()<\/a>&#8216; method will return an ID of a document that is in a form of a randomly generated UUID.\u00a0 In the sample app for iOS, an &#8216;NSDictionary&#8217; is created to correspond to an &#8216;NSObject&#8217; in Objective-C with properties of &#8216;text&#8217;, &#8216;check&#8217; and &#8216;created_at&#8217; defined.\u00a0 Below for ..<\/p>\n\n\n\n<p><strong>iOS<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\r\n    NSDictionary *document = @{@&quot;text&quot;:       text,\r\n                               @&quot;check&quot;:      @NO,\r\n                               @&quot;created_at&quot;: [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: @&quot;Couldn&#039;t save new item&quot; forError: error];\r\n    }\r\n<\/code><\/pre>\n\n\n\n<p>we create the new document&#8217;s properties and then save the document by referencing the datebase for the &#8216;createDocument()&#8217; method.\u00a0 The &#8216;JSONObjectWithDate&#8217; is an utility function for taking a Cocao date object and converts into an ISO8601 String format as dates cannot be stored as native objects in JSON.<\/p>\n\n\n\n<p>For Android, the &#8216;SimpleDateFormat&#8217; class is creating the &#8216;currentTimeString&#8217; for the object where the document ID is constructed by the combination of the &#8216;currentTime&#8217; from the &#8216;Calendar&#8217; class and the UUID from the &#8216;randomUUID()&#8217; method.\u00a0 Referencing the &#8216;database&#8217; that was created from the Manager class, a document is created by calling the same &#8216;createDocument()&#8217; method as in iOS.\u00a0 In Android, Key-Value pairings resemble a HashMap object structure and so we create a Map that is the Java equivalent of the JSON object in the &#8216;properties&#8217; variable.\u00a0 The same three properties are inserted into the Java map by the &#8216;put()&#8217; method and then to persist to disk, the Map object is passed into the &#8216;putProperties()&#8217; method.\u00a0 This is illustarated below:<\/p>\n\n\n\n<p><strong>Android<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\r\n    SimpleDateFormat dateFormatter = new SimpleDateFormat(\r\n                                                   &quot;yyyy-MM-dd&#039;T&#039;HH:mm:ss.SSS&#039;Z&#039;&quot;);\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 + &quot;-&quot; + uuid.toString();\r\n\r\n    Document document = database.createDocument();\r\n    Map(String, Object) properties = new HashMap(String, Object)();\r\n    properties.put(&quot;_id&quot;, id);\r\n    properties.put(&quot;text&quot;, text);\r\n    properties.put(&quot;check&quot;, Boolean.FALSE);\r\n    properties.put(&quot;created_at&quot;, currentTimeString);\r\n\r\n    document.putProperties(properties);\r\n<\/code><\/pre>\n\n\n\n<p><strong>[3] Attachments<\/strong><\/p>\n\n\n\n<p>The <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/current\/develop\/guides\/couchbase-lite\/native-api\/attachment\/index.html\">Attachment<\/a> feature, though not used in the sample, allow documents to attach any arbitrarily size binary blob and thus is a technique on optimizing for replication where document updates are independent of attachment updates as they are stored separately from the JSON body.\u00a0 For example, this may be an use-case for when the meta-data, document JSON, is changed on an associated attachment and therefore if a document is updated without changes to an attachment, then the replicator can skip sending the attachment.<\/p>\n\n\n\n<p><strong>[4] Views<\/strong><\/p>\n\n\n\n<p>The <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/1.1.0\/develop\/guides\/couchbase-lite\/native-api\/view\/index.html\">View<\/a> allows applications to create and maintain secondary indexes using the map &amp; reduce technique.\u00a0 We start off with a JSON document and the Map Function is the function you write that takes that document as input and outputs a set of key-value pairs. \u00a0The output of that map function that runs across all documents in the database generates an index.\u00a0 In the Grocery Sync sample applicaiton, we are defining a View with a map function that indexes the to-do items by creation date.\u00a0 Creating a View for..<\/p>\n\n\n\n<p><strong>iOS<\/strong><\/p>\n\n\n<p>[crayon lang=&#8221;objective-c&#8221;]<br \/>\n[[theDatabase viewNamed: @&#8221;byDate&#8221;] setMapBlock: MAPBLOCK({<br \/>\n        id date = doc[@&#8221;created_at&#8221;];<br \/>\n        if (date)<br \/>\n            emit(date, nil);<br \/>\n    }) version: @&#8221;1.1&#8243;];<br \/>\n[\/crayon]<\/p>\n\n\n\n<p>For iOS, first we are creating a \u2018View\u2019 on the database. \u00a0The database is also a container or namespace for the \u2018Views\u2019 , so we say &#8216;viewNamed: @\u201cbyDate\u201d&#8217; where if the View does not exist already we will then create it and if it does, we will return it.\u00a0 The rest of the block of code is to set its Map Block. \u00a0So this is a MapReduce View and so it means it has a map function.\u00a0 We get the date out of the document by looking at the &#8216;created_at&#8217; property.\u00a0 And if the document has one, we emit that as the key. In the Grocery Sync app, it is not emitting anything for the value because it is actually going back to grab the document itself to get the rest of the data from.\u00a0 The version string, &#8216;@&#8221;1.1&#8243;&#8216; at the end is used to communicate with the database on whether or not your map function has changed.\u00a0 Since the database can not tell when the map function has changed from one run to the next; a technique is to increase the version string to tell the database to throw away the current index and rebuild it.<\/p>\n\n\n\n<p><strong>Android<\/strong><\/p>\n\n\n<p>[crayon lang=&#8221;objc&#8221;]<br \/>\n    com.couchbase.lite.View viewItemsByDate =<br \/>\n            database.getView(String.format(&#8220;%s\/%s&#8221;, designDocName, byDateViewName));<br \/>\n    viewItemsByDate.setMap(new Mapper() {<br \/>\n        @Override<br \/>\n        public void map(Map(String, Object) document, Emitter emitter) {<br \/>\n            Object createdAt = document.get(&#8220;created_at&#8221;);<br \/>\n            if (createdAt != null) {<br \/>\n                emitter.emit(createdAt.toString(), null);<br \/>\n            }<br \/>\n        }<br \/>\n    }, &#8220;1.0&#8221;);<\/p>\n<p>[\/crayon]<\/p>\n\n\n\n<p>This is the Java-Android version where similar to iOS, we call, &#8216;database.getView()&#8217; and then create the &#8216;map function&#8217; using some inner class syntax which in Java exists as a &#8216;Mapper()&#8217; object.\u00a0 The indexes are able to be updated on demand and useful information are able to be extracted from the document that you want to index where then the key-value can be emitted.\u00a0 Everytime where something changes, the map function gets fed that document. The map function calls a function called &#8217;emit()&#8217; which takes the \u2018key and value\u2019 as parameters.<\/p>\n\n\n\n<p>What the Grocery Sync application is doing here is generating the index of all the to-do item that is shorted by &#8216;key&#8217; and since the key is the time-stamp, the items will be chronologically ordered where the value strings are the names of the &#8216;to-do&#8217; items.\u00a0 The index also remembers the document ID of the document that emitted that key-value pair.\u00a0 So when you are querying and when you have a row in your query, you may use that to go back to the document, and fetch that entire row out of the database if you want to.\u00a0 The idea here is once you have this index, you would query it. The query mindset is done by saying either, &#8220;I want all the index entries with a particular key, or a set of keys, or a range of keys.&#8221;<\/p>\n\n\n\n<p><strong>[5] Queries<\/strong><\/p>\n\n\n\n<p>Queries can then look up a range of rows from a view, and either use the rows&#8217; keys and values directly or get the documents they came from from the document ID.\u00a0 In the code below, we are driving the table from a View Query by creating a query that is sorted by descending date where the newest items are displayed first.<\/p>\n\n\n\n<p><strong>iOS<\/strong><\/p>\n\n\n<p>[crayon lang=&#8221;objc&#8221;]<br \/>\n    CBLLiveQuery* query = [[[database viewNamed:@&#8221;byDate&#8221;] query] asLiveQuery];<br \/>\n    query.descending = YES;<\/p>\n<p>    \/\/ Plug the query into the CBLUITableSource, which uses it to drive the table.<br \/>\n    \/\/ (The CBLUITableSource uses KVO to observe the query&#8217;s .rows property.)<br \/>\n    self.dataSource.query = query;<br \/>\n    self.dataSource.labelProperty = @&#8221;text&#8221;;<br \/>\n[\/crayon]<\/p>\n\n\n\n<p>With the items in the index, we want to use that index to drive table view which is the main Grocery Sync UI.\u00a0 In iOS, we generate a query that is &#8216;viewNamed: @&#8221;byDate&#8221;&#8216; and call query which creates query on it.\u00a0 Then we see \u2018LiveQuery\u2019 where it is a special subset of query that will actually track the View over time. \u00a0We set the &#8216;descending&#8217; property on the query to \u2018yes\u2019 as we want to get the rows in descending order of the dates in to have the newest created items on top.\u00a0 Lastly with the\u00a0iOS specific code, we are telling the\u00a0&#8216;dataSource&#8217; about the query and indicating which property to show as the label in table view.<\/p>\n\n\n\n<p><strong>Android<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><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\n\n\n<p>Similarly, the Java-Android version starts up the same way where a query is created by having the view call &#8216;toLiveQuery()&#8217; on it to generate the &#8216;liveQuery&#8217;.\u00a0 And then &#8216;addChangeListener()&#8217; is executed on that liveQuery, followed by the &#8216;changed()&#8217; method being called for the Query updates, which is whenever the result of that Query changes.\u00a0 And the output for when you run the query is an array of \u2018QueryRows\u2019 where each QueryRow is an object and has properties like Key and Value and DocumentID but and also a document property which will load the document back out of the database.\u00a0 It is going through an &#8216;Iterator()&#8217; to get all the rows out of the query and add them to the &#8216;grocerySyncArrayAdapter&#8217; which is a custom class it has for storing the dataset.<br>\n<strong>[6] LiveQuery<\/strong><\/p>\n\n\n\n<p>We can think of LiveQuery as a wrapper around the query which listens for change notifications from the database.\u00a0 So when the database changes, the LiveQuery will kick off the Query again, re-running it in the background asynchronously.\u00a0 And then compare the query results with the previous results that it already had.\u00a0 If the results have changed, the LiveQuery will signal its own notification events which the application may then handle accordingly like redrawing the UI based on that new Query.\u00a0 Below, the code illustrates how to display the Table Cells for..<\/p>\n\n\n\n<p><strong>iOS<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><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[@&quot;check&quot;] boolValue];\r\n    if (checked) {\r\n        cell.textLabel.textColor = [UIColor grayColor];\r\n        cell.imageView.image = [UIImage imageNamed:@&quot;checked&quot;];\r\n    } else {\r\n        cell.textLabel.textColor = [UIColor blackColor];\r\n        cell.imageView.image = [UIImage imageNamed: @&quot;unchecked&quot;];\r\n    }\r\n    \/\/ cell.textLabel.text is already set, thanks to setting up labelProperty\r\n<\/code><\/pre>\n\n\n\n<p>For the sample application here, the &#8216;CBLUITableSource&#8217; from Couchbase Lite will act as an intermediary between the LiveQuery and the UITableView, receiving change notifications and thus driving the table based on a Query.\u00a0 It also acts the data source object for the tableView, which means that it is the object that the tableView is going to ask to provide all the data for the rows.\u00a0 Your &#8216;controller\u2019 object then becomes the delegate of the UITableView where it will get notifications from the TableView about when the user taps on one of the rows.<\/p>\n\n\n\n<p><strong>Android<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><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(&quot;check&quot;);\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(&quot;text&quot;);\r\n label.setText(groceryItemText);\r\n<\/code><\/pre>\n\n\n\n<p>Here is the Android equivalent in the Grocery Sync Adapter class. \u00a0It is getting the &#8216;QueryRow&#8217; by calling \u2018getItem()\u2019 based on the row number in the table. \u00a0It then gets the document from the Query Row and gets its current revision. Then it uses the check and text properties to populate the UI Controls in the row.<\/p>\n\n\n\n<p>Lastly for the Grocery Sync sample application, we need to actually respond to a tap on a row on the table such as toggling the check mark.\u00a0 Below we illustrate how this is done by referencing the\u00a0QueryRow at a particular index and retrieve the document out of it.<\/p>\n\n\n\n<p><strong>iOS<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><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&#039;s &#039;checked&#039; property:\r\n    NSMutableDictionary *docContent = [doc.properties mutableCopy];\r\n    BOOL wasChecked = [docContent[@&quot;check&quot;] boolValue];\r\n    docContent[@&quot;check&quot;] = @(!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: @&quot;Failed to update item&quot; forError: error];\r\n    }\r\n}\r\n<\/code><\/pre>\n\n\n\n<p>This is a method call upon the UITableView itself on its delegate.\u00a0 Telling that a row got selected which means \u2018TAPPED\u2019 So it is going to go to the data source. Which is the UI Table Source object, and ask it for the Query Row at that index, and get the document out of it. So now it is basically doing a Read, Write, Modify cycle on that document. Where it gets the properties..makes a mutable copy of the properties where we now have a mutable dictionary where we can update.\u00a0 Reads the checked property out as a Boolean, and writes it back in as the opposite. So this is inverting the Boolean value of the checked property. Then it calls putProperties in the end to save that value back in.<\/p>\n\n\n\n<p><strong>Android<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><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(&quot;check&quot;)).booleanValue();\r\n    newProperties.put(&quot;check&quot;, !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\n\n\n<p>Moving to the Android version now, we have an &#8216;onItemClick()&#8217; that gets called by the Android GUI.\u00a0 It is going to get its QueryRow at that position, get the document, get the properties out and then put the properties.\u00a0 In the Java APIs it is idiomatic to use exceptions where it is not in objective C so this has a try-catch wrapped around the handle in saving the document.\u00a0\u00a0 If in the Time Window something else modified the document, probably the replicator, then this would throw an error. You would get a conflict error.<\/p>\n\n\n\n<p>Next we will go into the Couchbase Lite Replicator class and the <a href=\"https:\/\/www.couchbase.com\/developers\/mobile\/\">Couchbase Mobile Developer Portal<\/a> is a great resource to start from.<\/p>\n\n\n\n<p><a href=\"https:\/\/bit.ly\/CBNYC2015\"><img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/wp-content\/uploads\/sites\/5\/2026\/05\/events.cbliveny.blog_.banner.png\"><\/a><\/p>\n\n\n\n<p>\u00a0From there we will dive into <a href=\"https:\/\/bit.ly\/sync_gateway\">Couchbase Sync Gateway<\/a> in our 102 session, where I will talk about <a href=\"https:\/\/bit.ly\/CBNYC2015_102\">&#8220;How to Add Secure Sync to your Mobile application.&#8221;<\/a>\u00a0 We will round out the day with how to enable the Peer-to-Peer feature of Couchbase Mobile in the 103 session with <a href=\"https:\/\/twitter.com\/agonyou\">Austin Gonyou<\/a>, where you can create unique social in-app experiences by &#8220;Building a Peer-to-Peer App with Couchbase Mobile.&#8221;<\/p>\n","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 Mobile App&#8221; slides, we explored the APIs of Couchbase Mobile by walking over the Grocery [&hellip;]<\/p>\n","protected":false},"author":30,"featured_media":18,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[131,9,132],"tags":[],"ppma_author":[107],"class_list":["post-338","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-couchbase-lite","category-couchbase-mobile","category-objective-c"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.6 (Yoast SEO v27.6) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\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=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/couchbase-nosql-dbaas.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1800\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\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\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\\\/\"},\"wordCount\":2299,\"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\\\/5\\\/2026\\\/05\\\/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\\\/5\\\/2026\\\/05\\\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2015-10-23T08:09:44+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\\\/5\\\/2026\\\/05\\\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/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\\\/sites\\\/5\\\/2026\\\/06\\\/logo.svg\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/06\\\/logo.svg\",\"width\":\"1024\",\"height\":\"1024\",\"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:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b912c9a97568a859697ee195432d0bd7cc3ed67d720ae2e6588b67313fa49e08?s=96&d=mm&r=g650445f1ea30314c4f3555dd680154f5\",\"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":"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.","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","og_image":[{"width":1800,"height":630,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/couchbase-nosql-dbaas.png","type":"image\/png"}],"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","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-live-new-york-couchbase-101-how-to-build-your-first-couchbase-mobile-app\/"},"wordCount":2299,"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\/5\/2026\/05\/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\/5\/2026\/05\/couchbase-nosql-dbaas.png","datePublished":"2015-10-23T08:09:44+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\/5\/2026\/05\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/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\/sites\/5\/2026\/06\/logo.svg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/06\/logo.svg","width":"1024","height":"1024","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:\/\/secure.gravatar.com\/avatar\/b912c9a97568a859697ee195432d0bd7cc3ed67d720ae2e6588b67313fa49e08?s=96&d=mm&r=g650445f1ea30314c4f3555dd680154f5","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\/"}]}},"acf":[],"authors":[{"term_id":107,"user_id":30,"is_guest":0,"slug":"william-hoang","display_name":"William Hoang, Mobile Developer Advocate, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/338","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=338"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/338\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media\/18"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media?parent=338"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/categories?post=338"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/tags?post=338"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/ppma_author?post=338"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}