Copy of Original Draft Score by Handel
Photo courtesy of Adrian Pallant with permission under license CC BY-SA 2.0
The U in CRUD
In this earlier post, I wrote about getting started with basic CRUD operations in Couchbase Lite on Android. In this quick note, I want to go a little deeper on document updating. This will open the door to a whole new set of issues. Let’s take a peek inside.
Couchbase Lite is a document-oriented database. The documents are stored as JSON objects. As described in the previous post, it’s easy to work with the document contents directly. They’re stored in the document object as a map. That fits nicely with native ways of manipulating the contents.
Tweaking the direct approach
When you retrieve a document, you get a copy which contains an immutable version of the data. You can deal with this by copying the map into a separate map object, then overwriting the old map. That’s shown in this code snippet:
1 2 3 4 5 6 7 8 9 |
profile = new HashMap<>(); profile.putAll(document.getProperties()); profile.put("type", "profile"); // Add a "type" to the document try { document.putProperties(profile); } catch (CouchbaseLiteException ex) { Log.e(TAG, "CBL operation failed"); } |
This actually creates a new revision of the document, using the new document body.
Alternatively, you can use createRevision()
to obtain a new UnsavedRevision
. This returns a copy of the latest revision, but with mutable contents. You can then manipulate the properties map directly. Changes are committed by calling save()
. This code snippet has the same end effect as the previous one:
1 2 3 4 5 6 7 8 9 |
UnsavedRevision update = document.createRevision(); profile = update.getProperties(); profile.put("type", "profile"); // Add a "type" to the document try { update.save(); } catch (CouchbaseLiteException ex) { Log.e(TAG, "CBL operation failed"); } |
Revisions, you say?
That’s great for a lot of applications. I haven’t said much about revisions yet. You get the idea that a document is changing. Couchbase Lite has a notion of document revisions to go along with those changes.
Revisions go deeper than just tracking a linear set of changes, though. What doesn’t jump out from examples like the ones I have shown is the possibility of conflicts. Conflicts occur when more than one update of a specific document revision gets committed back to the database.
Think of it just like a real world document. Maybe you write an article (or a blog post!) and send it around to several people for comments. You get one set of comments back and make some changes. Then another set of comments come back, based on the same original document. Do this often enough and you’re almost guaranteed to hit the case where some changes overlap. (Well, for software devs, probably the better example is in merge conflicts when using source control.) Conflict!
DocumentUpdater
Dealing with document conflicts, revision history, and so on, is more than I want to address in this post. But we can get a glimpse of how Couchbase helps. This last approach to updating may seem like overkill, but you’ll come to appreciate it once conflict resolution come into play. Here’s the code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
document = database.getDocument(documentId); try { document.update(new Document.DocumentUpdater() { @Override public boolean update(UnsavedRevision newRevision) { Map<String, Object> properties = newRevision.getUserProperties(); properties.put("type", "profile"); newRevision.setUserProperties(properties); return true; } }); } catch (CouchbaseLiteException ex) { Log.e(TAG, "CBL operation failed"); } |
Wow, this looks a lot more complex than the earlier examples. It’s really only a little more complicated. That added structure ends up making life a lot easier. So what’s happening?
This construction lets Couchbase Lite deal with the grunge work of handling conflicts. You define a callback based on the DocumentUpdater
interface. Couchbase Lite will take care of creating a new UnsavedRevision
instance, just like in the earlier example. Your method then needs to make the changes you want. On return, Couchbase Lite automatically tries to save the document. If it detects a conflict Couchbase Lite simply calls update()
again. Return true
if you’ve made changes you want saved, or false
otherwise.
If you want to learn more about revisions, collisions, and conflict resolution, take a look at our guide here
This post originally appeared on http://blog.couchbase.com/.