CouchDB 实例
在这个小节中,我们将开发一个简单的 CouchDB 的应用,这个应用用以保存个人的联系人 名单,然后创建一个设计文档,其中包含 3 个 view,分别用以查询联系人中年龄大于 10 岁的,小于 5 岁的,以及联系人所在的公司为”Infonet”的。
我们通过 JavaScript 来进行所有的这些操作,因此我们需要封装一些常用的操作:
- 创建数据库
- 添加联系人(文档)
- 添加视图
- 查询数据
创建数据库非常容易,以 PUT 方式访问需要建立的数据库的 URL 即可:
//PUT http://localhost:5984/contacts
function create_couch_db(host, port, dbname, handler){
host = host || "localhost";
port = port || "5984";
if(!dbname){
return false;
}
var xhr = new XMLHttpRequest();
var url = "http://"+host+":"+port+"/"+dbname;
println(url);
xhr.open("PUT", url, false);
xhr.send(null);
function complete(){
if(xhr.readyState == 4){
handler(xhr);
}
}
xhr.onreadystatechange = complete;
}
此处的 XMLHttpRequest 是一个用 Java 做的简单实现,不支持 POST 数据。对于 POST 的请求,我们在随后再做介绍。create_couch_db 函数的最后一个参数是一个函数,当回调发生时调用此函数。
比如我们要在本机上部署的 CouchDB 创建一个名为”contacts”的数据库,当完成时我们将服务端返回的 JSON 解析并打印出其中包含的信息:
function complete(xhr){
var obj = JSON.parse(xhr.responseText);
for(var item in obj){
if(typeof obj[item] == "object"){
println(JSON.stringify(obj[item]));
}
println("key = "+item+",
value="+obj[item]);
}
}
create_couch_db("localhost", "5984", "contacts", complete);
调用之后,我们得到以下结果:
key = id, value=3e1a1b09536ee010352d79fd89000961
key = ok, value=true
key = rev, value=1-122ac58db939abb4aaf227accf5405b7
我们再来添加文档,首先定义几个联系人的信息:
var contacts = [
{
name : "John",
age : 28,
address : "Somewhere in Kunming",
interests : ["trevaling", "reading"],
phone : "(871)-1234567"
},
{
name : "Nelson",
age : 35,
company : "Infonet",
address : "Eest Black-bridge"
},
{
name : "Boycott",
company : "Infonet"
},
{
name : "Smith",
age : 27,
company : "Infonet",
},
{
name : "Jim",
address : "West Mountain",
phone : "(871)-7654321"
},
{
name : "SiJing",
address : "HeBei",
age : 3
},
];
然后在一个循环中调用添加文档的接口,前面的那个 XMLHttpRequest 对象不支持 POST,我们只好自行开发一个可以发送 HTTP 请求的 JavaScript 脚本:
for(var i = 0; i < contacts.length; i++){
add_couch_doc_raw("http://localhost:5984", "contacts", \
contacts[i], complete_raw);
}
add_couch_doc_raw 函数将用以创建文档,并通过 complete_raw 函数将结果呈现出来:
function add_couch_doc_raw(uri, dbname, doc, handler){
var url = new java.net.URL(uri+"/"+dbname);
var data = JSON.stringify(doc);
var con = url.openConnection();
con.setDoOutput(true);
con.addRequestProperty("Content-Type", "application/json");
var writer = new java.io.OutputStreamWriter(con.getOutputStream());
writer.write(data);
writer.flush();
writer.close();
var reader = new java.io.BufferedReader(
new java.io.InputStreamReader(con.getInputStream()));
var line, text='';
while((line = reader.readLine()) != null){
text += line;
}
reader.close();
if(handler){
handler(text);
}
}
完成之后的 complete 接收服务端的 JSON 字符串:
function complete_raw(raw){
var obj = JSON.parse(raw);
for(var item in obj){
println("key = "+item+", value="+obj[item]);
}
}
运行之后,服务器将返回结果:
key = id, value=46efa16cc220f6548696a6e6fc0044f4
key = ok, value=true
key = rev, value=1-485b14c13e90cfad44d539a3860dc1f3
key = id, value=46efa16cc220f6548696a6e6fc004f83
key = ok, value=true
key = rev, value=1-a22f80d27046f1b46ae218788747ffdb
key = id, value=46efa16cc220f6548696a6e6fc005855
key = ok, value=true
key = rev, value=1-fc222c18f52f463c44ac48328b10385c
好了,现在我们可以通过 CouchDB 的 web 界面来查看刚才创建的数据库以及数据库中的文档了:
下面我们来尝试创建一个设计文档,并在设计文档中添加一些 view:
{
"_id" : "_design/filters",
"views" : {
"gt10" : {
"map" : "function(doc){
if(doc.name && doc.age){
if(doc.age > 10){
emit(doc.name, doc.age);
}
}
}"
},
"lt5" : {
"map" : "function(doc){
if(doc.name && doc.age){
if(doc.age < 5 ){
emit(doc.name, doc.age);
} }
}"
},
"infonet" : {
"map" : "function(doc){
if(doc.name && doc.company){
if(doc.company == 'Infonet'){
emit(doc.name, doc.company)
}
}
}"
}
}
}
我们为设计文档添加了三个 view,其中的 map 将用作过滤器,它将对所有的文档进行抽 取转换。将这个设计文档保存为文本,并通过 curl 上传该文档:
$ curl -X PUT http://localhost:5984/contacts/_design/filters \ -d @contacts-filter.js
这个设计文档的名称叫做 filters,因此完整的路径为/contacts/_design/filters。 现在我们就可以使用 view 来进行数据的过滤了,比如我们要找出所有联系人中,在 Infonet 公司工作的人:
当然,我们可以通过自己编写 JavaScript 来访问这些数据:
function filter_couch_data(host, port, dbname, doc, view, handler){
host = host || "localhost";
port = port || "5984";
if(!dbname || !doc || !view){
return false;
}
var xhr = new XMLHttpRequest();
var url =
"http://"+host+":"+port+"/"+dbname+"/_design/"+doc+"/_view/"+view;
xhr.open("GET", url, false);
function complete(){
if(xhr.readyState == 4){
handler(xhr);
}
}
xhr.onreadystatechange = complete;
xhr.send(null);
}
访问 http://localhost:5984/contacts/_design/filters/_view/infonet 即可:
filter_couch_data("localhost", "5984", "contacts",
"filters", "infonet", complete);
当插入新的数据时,map 可以自动的将符合条件的 key/value 对放入 view,比如:
var newguy = {
age : 30,
name : "Fire"
};
add_couch_doc_raw("http://localhost:5984", "contacts", newguy, complete_raw);
filter_couch_data("localhost", "5984", "contacts", "filters", "gt10", complete);
我们新添加了一个 newguy,他的年龄为 30,然后我们访问 gt10 这个 view,可以看到,符合这个条件的记录多了一条。这一点与关系数据库中的 query 的效果相同。
{$ activeFileHint $}