This post is also available in: Italiano

⏱ Reading time: 8 min

One of the ingredients to make a good app is use a good database, such as Couchbase Lite. So, in this article we will see how to easily integrate Couchbase Lite in a iOS app.

Please accept YouTube cookies to play this video. By accepting you will be accessing content from YouTube, a service provided by an external third party.

YouTube privacy policy

If you accept this notice, your choice will be saved and the page will refresh.

What is Couchbase Lite?

Couchbase Lite the mobile SDK of the Couchbase suite. An SDK to allow developers integrate easily a NoSQL database to the mobile app.

Integrazione di Couchbase su Mobile e su Web
Couchbase integrations

Couchbase Lite SDK for iOS: hands on

To do that we will go through the CRUD operations and for each we will see the mandatory steps to follow.

C as “Create”

Well, the first action we want to do is create our first document with Couchbase. Couchbase has one method to create a document, saveDocument(_ document:concurrencyControl:).
That method accept two parameters. The first is the document (CouchbaseLiteSwift.MutableDocument) to be save, the second is an optional parameter (CouchbaseLiteSwift.ConcurrencyControl) that allow user to choice if resolve automatically possible conflicts or throw an exception to allow user manage manually the resolution. The default value islastWriteWins.

How to use saveDocument method?

First we need a database instance (CouchbaseLiteSwift.Database), so just init a new database.

do {
    let database = try Database(name: "DatabaseName")
} catch {
    ...
}

Then we need to create the document we want to save. So, create a new document (CouchbaseLiteSwift.MutableDocument) and add some fields.

let doc = MutableDocument(id: "MyUniqueDocumentIdentifier")
doc.setString("Mickey", forKey: "name")
doc.setString("Mouse", forKey: "surname")
doc.setInt(91, forKey: "age")
doc.setString("Contact", forKey: "type")

Finally, just save.

do {
    try database.saveDocument(doc, concurrencyControl: .lastWriteWins)
} catch {
    ...
}

As you saw, create and save a document with Couchbase is really simple and intuitive.

Tips and Tricks

Typing: in the document i added a field named “type” (doc.setString("Contact", forKey: "type")). This is a trick to allow easily split document in types and facilitate read operations. We will see later how to use this field.

Id: you don’t need to provide an id when you create a document. It’s a optional field, if you don’t, Couchbase generate a UUID for you.

Document creation: If you want, you can create a Document from a Dictionary (or a key-value map) simply passing the dictionary as parameter on the document constructor’s.

R as “Read”

Now that we have created our first document we want also to read it and why not, also display it in a list. Let’s see how to do it.

There are two ways to retrieve a document:

1. Get by id
2. Query

Get by id

To retrieve a document using its id we first need a database instance as for read operation.

do {
    let database = try Database(name: "DatabaseName")
} catch {
    ...
}

Then we can use method document(withID:...) that wants as parameter the id of the document to retrieve. The return type of this method is an optional document object (CouchbaseLiteSwift.Document?) that will be nil if document doesn’t exist.

let doc = database.document(withID: "MyUniqueDocumentIdentifier")

Query

As for get by id operation we need an instance of the database also for the query.

do {
    let database = try Database(name: "DatabaseName")
} catch {
    ...
}

The next step is create the query. To do this we need to use the metalanguage N1QL. N1QL allow user to define a query with a SQL-like sintax on a NoSQL database. Let see the example below.

let query = QueryBuilder
  .select(SelectResult.all())
  .from(DataSource.database(database))
  .where(
    Expression.property("type")
      .equalTo(Expression.string("Contact"))
  )

In this way we defined a simple query that search all documents (with all field of course) from the database where the field type is equal to Contact

We just have to run the query and we receive as result a result set containing all the documents that observe the query options.

do {
    let result = try query.execute()
} catch {
   ...
}

The object result conform to iterator Iterator, so can be iterated to get each document and do stuff. The result returned by the the query is a snapshot of the data at the moment of the execution. The documents changes afterwards will not be considered.

Tips and Tricks

Query listener: Couchbase Lite provide also another method to execute queries. This second method allow user not only retrieve data from built query but also listening future changes. Do this is as much simple as first method. Look!

let token = query.addChangeListener { queryChange in
    let results = queryChange.results?.allResults()
}

The listener will be invoked every time that the documents included in the query result changes. The token returned from the addChangeListener methods can be used to stop listen as follow.

query.removeChangeListener(withToken: token)

Document conversion: as for the creation you can easily convert a Couchbase to a dictionary (and viceversa) using toDictionary() method.

U as “Update”

Good, now that we are able to create and read documents to Couchbase why not update ours document?

Update document is very similar to create one. You only need to get document to update, update it, and save it again. Let see how.
Init the database.

do {
    let database = try Database(name: "DatabaseName")
} catch {
    ...
}

Retrieve the document to update…

let doc = database.document(withID: "MyUniqueDocumentIdentifier")

… and edit it.

let docToUpdate = doc.toMutable()
docToUpdate.setString("Male", forKey: "gender")

Of course save all.

do {
    try database.saveDocument(docToUpdate, concurrencyControl: .lastWriteWins)
} catch {
    ...
}

D as “Delete”

Least but not last, deletion. Maybe we want to delete some document, here how can be done.

As always we need our database.

do {
    let database = try Database(name: "DatabaseName")
} catch {
    ...
}

Similar to the update operation we should retrieve the document to delete. So, use document by id method.

let doc = database.document(withID: "MyUniqueDocumentIdentifier")

And now we can use deleteDocument(_ document: concurrencyControl:) method to delete a document. As for saveDocument, we can choose if resolve conflicts manually or automatically keeping the last.

do {
    try database.deleteDocument(doc, concurrencyControl: .lastWriteWins)
} catch {
    ...
}

Conclusions… or not?

Great, from now we are able to integrate Couchbase Lite to ours apps.
What we saw?

  1. Create a document
  2. Read a document (or many) with realtime update if we want
  3. Update a document (not so different to creation)
  4. Delete a document

What else can you want? I think nothing. 😄

I’m jokin. Because the cherry on the cake arrives just now. Yes because Couchbase provides another wonderful feature.

Synchronization between Couchbase Lite and Server

Sync is one of the my favorite functionality of Couchbase. Because it is as simple as it is effective. 

Couchbase Lite provides the ability to locally synchronize an instance of a remote database that resides on a Couchbase Server. All or part of it.
The Sync takes place through the Sync Gateway, which communicates with Couchbase Server and determines the changes to be propagated to the client. The client SDK connects to the Sync Gateway via a websocket protocol. For replication we use the Couchbase Replicator.

do {
    let database = try Database(name: DatabaseName)
} catch {
    ...
}

What i need to init a replicator object (CouchbaseLiteSwift.Replicator)?

I need a configuration object where only mandatory field is the url of the Sync Gateway from our Couchbase Lite. The others optional fields are, for example, replicatorTypewith which it is possible to choose the directionality of the replica with respect to the client, that is, if it must workpush, pull, or both. Another field for configuring replication è continuous: a flag that allow configure if replication should be run one time or continuously.

let targetEndpoint = URLEndpoint(url: "ws://localhost:4984/bucketname/")
 
let replConfig = ReplicatorConfiguration(database: database, target: targetEndpoint)
replConfig.replicatorType = .pushAndPull
replConfig.continuous = true
replConfig.authenticator = BasicAuthenticator(username: "user", password: "pwd")
 
let replicator = Replicator(config: replConfig)

With the replicator object we need only start the replication…

replicator.start()

… or stop it.

replicator.stop()

Tips and Tricks

Listen replication status: as for the query, also for the replication we can add a listener to receive changes of replication status. Below the code.

let token = replicator.addChangeListener { changes in
    let status = changes.status
}

As for the queries, the token should be used to remove the listener to the replicator.

replicator.removeChangeListener(withToken: token)

Conclusions about Couchbase Lite

Couchbase Lite, as part of the Couchbase suite, is a powerful arrow for the bow of a mobile developer. In this article we have covered only a small part of its potential. Being a technology full of possibilities and facets, our advice is to deepen the functionality of Couchbase, also reading the next articles in this section, to allow you to have full control of the database of your apps and more. In addition, you will understand how this solution can best suit your needs.

Are you curious to know more? Go to the next article in the series by clicking here.

See you soon!