Sunday, July 10, 2011

Usage of DocumentReferences in ektorp for CouchDB

We are using ektorp as a java API for CouchDB and had a scenario of parent/child documents, though document based databases should not be used in the cases were there is a need for relational data, in practical world we end up having some sort of relationships between multiple documents (eg: parent/child etc). The primary reason being the choice of the document based database itself.
People go for databases like CouchDB not because there is a need for schema less data but for the other cool features these databases gives us like replication (master to master), conflict resolution etc., which can be leveraged to have a offline capability for applications. I think this itself is the smell, features like these should not drive one to use NoSQL databases, because the application domain needs the relational data.
Any ways the choice is made (yet to be challenged) and we had to figure out how to model our documents and persist in the database which has the parent/child relationship. CouchDB itself does not care how we store documents its up to the API to manage these relationships. Ektorp provides a way to achieve this (however its bit flaky, will cover the details at the end of this post)
Lets take an example which is quoted in the documentation of Ektorp itself, a BlogPost and a bunch of Comments. What if we want to store a BlogPost and Comment as different documents, can we add comments to the blog post and just by saving blog post does it save all the comments as individual documents ? the answer is yes, its is possible with @DocumentReferences annotation.

Blog post has a collection of comments, having a @DocumentReferences annotation on the collection comments will enable us to save a blog post by adding comment and the comment is saved as a separate document behind the scenes. However there is a trick to get this working.
1. The cascade property in the @DocumentReferences annotation, it has to be either set to ALL or SAVE_UPDATE to get this working.
2. Comment (which is a child in this case) should have a back reference to the parent with its id (blogPostId in this case) and the same has to be specified in the @DocumentRefernces annotation.
3. The most important thing is while adding a comment to the blogPost, this back reference in the comment has to be set manually. This means that before adding any children to the parent, the parent has to be persisted in the database before only then we will have the id generated for the parent which can be set as a back reference in the children. We expect typical ORM like hibernate to do this automatically for us in case of traditional RDBMS but in with ektorp we have to take care of all this manually.
Find the test below which demonstrates all the three points above.

Notice that in the test, BlogPost if first created and persisted, post which a new comment is added to the blog post and just the blog post is updated this operation will create a comment as a separate document (behind the scenes). Like I mentioned before while adding a comment to the blogPost we should also set the blogPostId (backreference) in the comment explicitly.

Ektorp has documented the limitations of this usage but the example itself is not very clear hence this post :)