O CouchDB é um banco de dados Orientado a Documentos. Isso significa que cada valor armazenado é um documento, e como tal, possui uma identificação única, uma revisão, e chaves/valores, que serão as informações do documento. Pensando dessa forma, várias coisas são melhores para serem classificadas assim do que em tabelas.
Existem duas formas de você utilizar os documentos, uma é fazendo dele como um documento real, e armazenar todas as informações possíveis dentro dele. A segunda forma é fazer referência à um outro documento. Existe uma diversidade da “melhor prática” no CouchDB, onde cada um dos desenvolvedores tem uma visão diferente. O J. Chris, por exemplo, desencoraja o uso, a não ser que seja realmente um caso onde não tem como não se usar vários documentos.
Quem usa Ruby, tem nas suas mãos várias ferramentas para trabalhar com CouchDB. Eu uso o CouchRest, que é uma biblioteca feita em Ruby pelos criadores do CouchDB. Ela é simples e bem fácil de usar. Com ela você pode definir modelos para sua aplicação:
COUCHDB = CouchRest.new
COUCHDB_SERVER.default_database = "your_database"
use_database COUCHDB_SERVER.default_database
end
Você não precisa definir nenhuma regra, a única coisa que vai ser inserida nesse documento é o couchrest-type. Onde ele define o tipo de documento:
>> article = Article.create(:title => "A melhor banda")
=> {"title"=>"A melhor banda", "_rev"=>"1-2513717810", "_id"=>"69d8dac29a0b112707b280eec4374a59", "couchrest-type"=>"Article"}
>> article['title']
=> "A melhor banda"
Quando você define no modelo o método property, ele adiciona automagicamente os gets/sets para a propriedade:
use_database COUCHDB_SERVER.default_database
property :title
property :author
end
>> article = Article.create(:title => "A melhor banda", :author => "Cairo Noleto")
=> {"title"=>"A melhor banda", "_rev"=>"1-3604901785", "_id"=>"2fe349c08d7d3150968b8de7b719d5d1", "author"=>"Cairo Noleto", "couchrest-type"=>"Article"}
>> article.title
=> "A melhor banda"
>> article.author
=> "Cairo Noleto"
O CouchRest possui uma forma de declarar vários documentos em um só:
COUCHDB = CouchRest.new
COUCHDB_SERVER.default_database = "your_database"
use_database COUCHDB_SERVER.default_database
property :title
property :authors, :cast_as => ["Author"]
end
Assim, quando você armazenar esse documento via CouchRest, ele vai colocar todas as propriedades desse documento dentro do mesmo documento:
>> a = Article.create(:title => "A melhor banda do mundo!", :authors => [Author.create(:name => "Cairo Noleto")])
=> {"title"=>"A melhor banda do mundo!", "_rev"=>"1-2417824677", "_id"=>"bfeaa06ad41bd8bdda50290ef10cbc5d",
"authors"=>[{"name"=>"Cairo Noleto", "_id"=>"f80f56083917f8b651495f2a445b4df0", "_rev"=>"1-2108444623",
"couchrest-type"=>"Author"}], "couchrest-type"=>"Article"}
>> a.authors.first['name']
=> "Cairo Noleto"
>> a.authors.first.class
=> Author
Uma outra forma de se fazer isso é armazenar apenas a referência do documento nesse documento e usar uma view pra recuperar todos os documentos:
COUCHDB = CouchRest.new
COUCHDB_SERVER.default_database = "your_database"
use_database COUCHDB_SERVER.default_database
property :title
property :authors, :cast_as => ["String"]
end
>> a = Article.create(:title => "Ben 10 - Como funciona", :authors => [Author.create(:name => "Cairo Noleto").id])
=> {"title"=>"Ben 10 - Como funciona", "_rev"=>"1-3102640010", "_id"=>"e7e6085ca37e7fe1da80273e0dea6fe0",
"authors"=>["a7fbb1522fc613a0a54da3c9c075ca04"], "couchrest-type"=>"Article"}
>> a.authors.first.class
=> String
>> a.authors.first
=> "a7fbb1522fc613a0a54da3c9c075ca04"
Para recuperar todos os documentos nesse caso, iremos fazer uma view:
COUCHDB = CouchRest.new
COUCHDB_SERVER.default_database = "your_database"
use_database COUCHDB_SERVER.default_database
property :title
property :authors, :cast_as => ["String"]
view_by :all_documents,
:map => "
function(doc) {
if (doc['couchrest-type'] == 'Article') {
for (var i in doc['authors']) {
emit(doc['authors'][i], null);
}
} else if (doc['couchrest-type'] == 'Author') {
emit(doc['_id'], null);
}
}"
end
>> Article.by_all_documents
=> [{"title"=>"Artigo: 0.290891879003595", "_id"=>"2c4680c3772b984195d18043f45ca574", "_rev"=>"1-1057019809",
"authors"=>["97cc55b7c6124c54b1a2b1b111285294"], "couchrest-type"=>"Article"}, {"name"=>"Nome 0.807179829913082",
"_id"=>"97cc55b7c6124c54b1a2b1b111285294", "_rev"=>"1-1103209569", "couchrest-type"=>"Author"}]
Assim você pode recuperar todos os documentos, sendo artigos ou autores. A diferença é que ele leva em consideração todos os documentos, ele realmente traz do CouchDB todos os documentos, já no CouchRest não, ele traz apenas o documento, os documentos aninhados são instanciados, eles não foram recuperados de seus documentos reais.
Assim, o CouchRest não lida com os documentos que mudaram de revisão, por quê ele cria as instâncias dos documentos aninhados a partir do documento. Do ponto de vista do CouchDB, ele não está trazendo os documentos aninhados com a ultima revisão, por quê ele não está pegando esses outros documentos.
O CouchRest trabalha da forma como o J. Chris desenhou o CouchDB, com um documento apenas. A necessidade de relação em documentos pode existir quando nesses casos, você precisa desses documentos em outros locais da sua aplicação. Se você quiser continuar da forma “CouchRest” você tem que preparar para que sua aplicação trabalhe de forma que ela sempre mantenha todos as revisão nas mais atuais (Ou talvez você nem precise dessa informação atualizada!).
De um jeito ou de outro, você vai ter que aprender como funciona as views e map-reduce. Você sempre vai ter que fazer alguma coisa nesse sentido dentro do CouchDB.


Opa! Muito bom artigo, parabéns!