|
Tutorial
How to use jcouchdb in your java applications. IntroductionJcouchdb should support all features of CouchDB 0.8. The Database classThe org.jcouchdb.db.Database class is your main point of interaction with couchdb. Let's see some simple code: // create a database object pointing to the database "mycouchdb" on the local host
Database db = new Database("localhost", "mycouchdb");
// create a hash map document with two fields
Map<String,String> doc = new HashMap<String, String>();
doc.put("foo", "value for the foo attribute");
doc.put("bar", "value for the bar attribute");
// create the document in couchdb
db.createDocument(doc);This creates a simple Document with two fields based on a HashMap. Note that the database has to already exist for it to work. Databases can be created via Futon or with the org.jcouchdb.db.ServerImpl class. DocumentsJcouchdb offers many different ways of using java classes as !CouchDB documents. You can work totally schema-free and without any type constraint and use a Java object graph composed of list and map instances or you can use your own Java classes with strict type constraints or you can have something in between. it's your choice. Jcouchdb depends on the svenson JSON library which in fact used to be a part of jcouchdb. To fully understand the possibilities of working with svenson you should go and read the svenson documentation. Here I will only show you the jcouchdb specific parts. First there is the org.jcouchdb.document.Document interface which you can implement in your Documents. package org.jcouchdb.document;
import org.svenson.JSONProperty;
/**
* Interface for Documents used with jcouchdb.
*
* You don't actually have to implement Document, but your class needs
* to be able to be fed both "_id" and "_rev" properties -- but without
* those properties you cannot really work with couchdb anyway.
*
* @author shelmberger
*
*/
public interface Document
{
@JSONProperty( value = "_id", ignoreIfNull = true)
String getId();
void setId(String id);
@JSONProperty( value = "_rev", ignoreIfNull = true)
String getRevision();
void setRevision(String revision);
}There is also a convenience base class org.jcouchdb.document.BaseDocument which implements the Document interface and org.svenson.DynamicProperties which allows its subclasses to have both java properties and additional arbritrary properties. Design documentsorg.jcouchdb.document.DesignDocument lets you work with CouchDB design documents. There is also a small utility class org.jcouchdb.util.CouchDBUpdater that lets you keep the design document definitions outside of CouchDB and update CouchDB with them. ViewsThe database class also offers ways to query views and ad hoc views. import org.jcouchdb.db.Options;
import org.jcouchdb.document.ViewResult;
...
// assume db to be a jcouchdb database object
ViewResult<Map> result = db.queryView("myDesignDocId/myViewId", Map.class, null, null);
// query with options
ViewResult<Map> result2 = db.queryView("myDesignDocId/myViewId", Map.class,
new Options().count(10), null);
// you can also specify a svenson JSONParser to parse the results with. This gives you optimal control over how the JSON is turned into java objects
ViewResult<Map> result2 = db.queryView("myDesignDocId/myViewId", null, parser);
// query a view including its documents and convert the documents to FooDocument
ViewAndDocumentsResult<Object,FooDocument> result = db.queryViewAndDocuments("foo/byValue", Object.class, FooDocument.class, null, null);
// query views by keys allows you to specify a list of keys you want to fetch
// Here we fetch the keys "doc-1" and "doc-2" out of the view "foo/byValue"
// (The key is the first argument given to the emit in your map function)
ViewResult<FooDocument> result = db.queryViewByKeys("foo/byValue", FooDocument.class, Arrays.asList("doc-1","doc-2"), null, null);
The view result gives you access to the total rows and offset of the query and to the converted documents. See the svenson JSONParser documentation of how to use the JSONParser in svenson. Examples in testsJcouchdb comes with a set of unit tests which you can also take a look at to see examples of how to use jcouchdb (most importantly org.jcouchdb.db.LocalDatabaseTestCase which runs some integration tests against local CouchDB server. AttachmentsThe attachment mechanism mirrors the functionality present in couchdb itself. You will only be able to indirectly use the data property contained in {@link Attachment} to create attachments inlined with the document. When you query a document with attachments, the attachments will have a null data property and the stub property will be set to true. This limitation has its origin in the way couchdb works and is deliberately kept that way to not introduce additional queries. To get the actual content of the attachment back, you have to use the Database#getMethod(String,String). CouchdDBUpdaterIn 0.7.1 I've added a small tool class that can help you update your design documents / views while being able to edit them in your favourite editor. You just have to set up a directory structure with all your design documents and views in them, like this:
couchdb-views/
foo/
byName.map.js
byName.reduce.js
you need one root directory in which you create a folder per design document. the name of the folder will be the name of the design document. Then you put a ".map.js" file for every map function and a ".reduce.js" for every reduce function and do something like this. import org.jcouchdb.util.CouchDBUpdater;
...
// assume db to be a Database object pointing to the database you want to update and
// dir a File object pointing to the directory structure desribed above.
CouchDBUpdater updater = new CouchDBUpdater();
updater.setDatabase(db);
updater.setDesignDocumentDir(dir);
updater.updateDesignDocuments();The updater will go through every definition he finds and check if the design document exists in the couchdb database exactly like he found it. if not, he will updated the design document. |
Can someone post an example of queryViewByKeys?
or Database.getDocument() ? (why does it need a Class<D> object?)
woa.. just discovered these comments. a little late.. I wish google code had sent me a mail about it.
@jmsachs
The reason is java generics or more specifically type erasure which means that the generic type information is not available at runtime. This is the reason for the Class<D> parameters and @JSONTypeHint.
Is there an example on how to use Options with a startkey and endkey which are compounds? E.g. starkey=["abc"]&endkey=["abc",2]
Regarding the compound keys:
Options o = new Options(); o.startkey("abc"); String compound = new String{"abc","2"}; o.endKey(compound);key, startKey and endKey are automatically JSON encoded by a default generator. You can pass List or Maps etc.
import java.util.Arrays new Options().startKey(Arrays.asList("abc")).endKey(Arrays.asList("abc", 2));If you don't want to use temporary options, you can also call an encoded options explicitly unencoded with a JSON string.
new Options().putUnencoded("startkey", "[\"abc\"]").putUnencoded("endkey", "[\"abc\",2]")This will be a little faster but can be quickly get bothersome when used with dynamic ranges or more complicated keys.
Where is "org.jcouchdb.spring.SpringCouchDBUpdater" located? Its not in the jcouchdb-0.10.0-3.jar file I downloaded. Also, will the Spring Updater only update the views if the views don't-exist/change?
A Javadoc would be really useful...
http://fforw.de/static/jcouchdb-javadoc/ , like the frontpage mentions ;)
I wished there was an easy way to have google code integrated javadoc.
org.jcouchdb.spring.SpringCouchDBUpdater was given up due to acute uglyness and the dir-based view updater being much nicer.
jcouchdb seems just right to me, have tried it out a little. But a small suggestion: clean up the doc a bit, this page included. I also tripped on this SpringCouchDBUpdater thing before reading your last comment. :-)
As usual, too much things to do and to little time to actually do so. I've removed the mentioning of it.
That was quick, thanks!
Suppose I want to query the database for documents whose keys start with a particular prefix value. Is there any method in Options class capable of doing this.
Since the all_docs view has the document ids as keys and you can specifiy a startkey and an endkey you can query the all_docs like this
// assume db to be a org.jcouchdb.db.Database instance ViewAndDocumentsResult<Object,BaseDocument> docs = db.query("_all_docs", Object.class, BaseDocument.class, new Options().startKey("5").endKey("7"), null, null); for (ValueAndDocumentRow<Object,BaseDocument> r : docs.getRows()) { System.out.println(r.getDocument()); }This would query every document with an id in between "5" and "7", basically all ids starting with "5" and "6" and the exact id "7".
Hi, Any tips on how to manage entity relationships such as the ones mentioned here http://wiki.apache.org/couchdb/EntityRelationship.
It would be good if jcouchdb could create these relationships on the fly maybe by using a annotation on a method to signify if its an embedded array or seperate document. e.g @Embedded or @Seperate. If its an unknown object e.g not a basic type string,int,etc or a collection then create that object if it doesnt have a _id. Im happy to contribute if you think this would be usefull.
It may also be good to use a annotation at the head of a document to define its type rather then using an extension. What do you think?
@darran
Generally it would be a good idea to provide further utilities that also help with entity relationships. I think it just would need to be an add-on (meaning you can do without/differently if you want).
I'm not quite sure how your @Embedded and @Separate would work.
I did some experiments with a type system on top of couchdb where a type field defines the type of a document and a special, auto-generated view helps you working with declared ID-reference fields in those documents. That seemed to be a good way which would also be in tune with the new document references in 0.11. As usual, time was the limiting factor here, but I could imagine reviving the idea to include it in jcouchdb.
How would your idea work?
First a disclaimer I`m new to CouchDB so I could be missing a trick and still be suffering from my relational brainwashing ;)
I was thinking that ,for example, when you passed an object to the createOrUpdate it could use reflection to look for @Embedded/@Seperate on any getters. It could then invoke the getter and serialise the Collection/Map/Object returned into either an embedded array in the parent object if @Embedded or create the object/s update CouchDB and add the id/s to the parent object. Obviously failure half way through could be an issue which would have to be handled or reported. If the child object had a id then it would be assumed to be an update rather then a create.
On retrieving the object it would again use reflection to detect the annotations on the class before its constructed then on parsing the JSON it would make a call to get the child class/collection from couchDB, construct it and once they`ve all been constructed add to the parent.
Obviously views would also have to be factored into it.
At the moment I think the only way I can deal with this ,if not using an embedded array, is if I store the ids of the child objects in my parent alongside the objects themselves and ensure the objects are ignored in the JSON serialisation. Which is going to make maintainability a bit difficult and isn`t very DRY. Alternativley I could try and use a TypeConverter? to create/get the child object but this may be a bit messy.
I guess on the getting side you could implement a form of lazy loading like Hibernate and proxy your class so when the get<children> method is invoked the child object is looked up in CouchDB.
I'm afraid that even an automated, annotation-based fetching of child-objects would still require you to use @JSONIgnore on the child object getters for it to work.
Have you taken a look at the linked document feature in 0.11 ? ( http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views#Linked_documents ) this would kind of handle your use case in another way..
I'm not really sure yet how to get this all together in a good impl.
Could you add support to stop continuous replication?
This is a little feature request / question. If there is some singleton instance of Svenson JSON parser inside jcouchdb, is it possible to get into it? And set e.g. type converters and stuff?
While jcouchdb doesn't have any singletons (bad design, bah!), you can actually confgure the instances returned by JSON.getDefaultJSON() and JSONParser.getDefaultJSONParser(). Note that this is highly dangerous as it works on the VM wide defaults for svenson.
If you look at the "hood" example application, you can see the way I would actually recommend, which is creating a JSONConfig instance you can resuse in your Databases/other layers. You can of course just create a system-wide Database instance and pass that around.
Is there a way to make include_docs work in conjunction with ChangeNotification??
Cheers, André
My databaseEventHandler is not being called when changing fields in my db after adding it with addEventHandler, what can be the cause of that, missing code wrong setup ?
The DatabaseEventHandler? only gets called for changes coming from within the same java VM / jcouchdb library. It was created at a time when there was no CouchDB changes API.
To get called for external / other-JVM changes you need to use org.jcouchdb.db.Database.pollChanges(Long, String, boolean, Options) or org.jcouchdb.db.Database.registerChangeListener(String, Long, Options, ChangeListener?).
@André
as it is now, there is no support for include_docs=true in jcouchdb.
I want to enter data into a couchDB document. I am using the following lines. db = dbSession.getDatabase("employee"); Document d = new Document(); d.setId("Any ID"); d.put("Name", "John"); d.put("Title", "IT Man"); d.put("Car", "SF02ECH"); d.put("Date", "16-07-2011");
d.put("Name", "Joe"); d.put("Title", "Java Dev"); d.put("Car", "SF04ECH"); d.put("Date", "17-07-2011");
Later when i check my CouchDB database i just get the following {
} Is there any way to add duplicate fieldnames in CouchDB.