一、CouchDB

1. CouchDB提供了JavaScript环境下基于MVCC(多版本并发控制, multi-version concurrency control)的文档存储

2. 在CouchDB里面添加或修改文档(记录)时,整个数据集都会保存到硬盘上,并且把老的版本标记为过时的。该记录的老版本内容依然会被整合到最新的版本里面去。每当创建了一个完整的新版本时,都会写入到连续的内存中,以便于更快地读取("最终一致性")。在大型的、可扩展部署中,多个实例有时会把较老(未同步)的记录发送给客户端,但对记录的所有修改最终会合并到主实例中

二、通过HTTP使用CouchDB

1. CouchDB通过REST方式把它所有的服务都开放了,因此在Node中使用CouchDB并不是必须用额外的模块

2. 通过HTTP获取CouchDB的数据库列表

const http = require('http')

http.createServer((req, res)=>{
    // 通过HTTP获取CouchDB的数据库列表
    http.get('http://127.0.0.1:5984/_all_dbs', (response)=>{
        let responseBody = ''
        response.on('data', (chunk)=>{
            responseBody += chunk
        })
        response.on('end', ()=>{
            res.writeHead(200, {'Content-Type': 'text/plain'})
            res.write(responseBody)
            res.end()
        })
    })
}).listen(8000, ()=>{
    console.log('Server running at http://127.0.0.1:8000')
})

3. 创建CouchDB数据库

const http = require('http')

http.createServer((req, res)=>{
    //  创建一个名为dbname的CouchDB数据库
    let options = {
        hostname: '127.0.0.1',
        port: 5984,
        path: '/dbname',
        method: 'PUT',
        auth: 'root:Q6$%xO0s'
    }
    let request = http.request(options, (response)=>{
        let responseBody = ''
        response.setEncoding('utf8')
        response.on('data', (chunk) => {
            responseBody += chunk
        });
        response.on('end', () => {
            res.writeHead(200, {'Content-Type': 'application/json'})
            res.write(responseBody)
            res.end()
        });        
    })
    request.end()
}).listen(8000, ()=>{
    console.log('Server running at http://127.0.0.1:8000')
})

4. 删除CouchDB数据库

const http = require('http')

http.createServer((req, res)=>{
    //  删除一个名为dbname的CouchDB数据库
    let options = {
        hostname: '127.0.0.1',
        port: 5984,
        path: '/dbname',
        method: 'DELETE',
        auth: 'root:Q6$%xO0s'
    }
    let request = http.request(options, (response)=>{
        let responseBody = ''
        response.setEncoding('utf8')
        response.on('data', (chunk) => {
            responseBody += chunk
        });
        response.on('end', () => {
            res.writeHead(200, {'Content-Type': 'application/json'})
            res.write(responseBody)
            res.end()
        });        
    })
    request.end()    
}).listen(8000, ()=>{
    console.log('http://127.0.0.1:8000')
})

三、使用node-couchdb

1. node-couchdb包简化了Node与CouchDB间的接口

# 安装CouchDB驱动
npm install felix-couchdb

2. 使用数据库

const couchdb = require('felix-couchdb')

const dbHost = '127.0.0.1'
const dbPort = 5984
const dbUser = 'root'
const dbPass = 'Q6$%xO0s'
const dbName = 'test'

const client = couchdb.createClient(dbHost, dbPort, dbUser, dbPass)

//  使用名为'test'的数据库
const db = client.db(dbName)
db.exists(function(err, exists){
    if(!exists){
        //  如果'test'数据库不存在
        //  则创建它
        db.create()
        console.log('Database ' + dbName + ' created.')
    }else{
        console.log('Database ' + dbName + ' exists.')
    }
})

3. 创建文档

const couchdb = require('felix-couchdb')

const dbHost = '127.0.0.1'
const dbPort = 5984
const dbUser = 'root'
const dbPass = 'Q6$%xO0s'
const dbName = 'test'

const client = couchdb.createClient(dbHost, dbPort, dbUser, dbPass)

const db = client.db(dbName)

let user = {
    name: {
        first: 'Shaoxiang',
        last: 'Gao'
    }
}

db.saveDoc('Gao', user, function(err, doc){
    //  创建了一个用户
    //  名为 Shaoxiang Gao
    //  并以'Gao'作为标识保存在数据库test中
    if(err){
        console.log(JSON.stringify(err))
    }else{
        console.log('Saved user.')
        //  现在可以打开浏览器
        // 输入地址http://root:Q6$%xO0s@127.0.0.1:5984/test/Gao
        // 访问该用户信息
    }
})

4. 读取文档

const couchdb = require('felix-couchdb')

const dbHost = '127.0.0.1'
const dbPort = 5984
const dbUser = 'root'
const dbPass = 'Q6$%xO0s'
const dbName = 'test'

const client = couchdb.createClient(dbHost, dbPort, dbUser, dbPass)

const db = client.db(dbName)

db.getDoc('Gao', function(err, doc){
    if(err){
        //  如果记录不存在
        //  回调函数的error参数会包含错误信息
        console.log(err)
    }else{
        console.log(doc)
        // =>
        // {
        //     _id: 'Gao',
        //     _rev: '1-4ad0a73ca5c5ebcd63464ffbfde7d72b',
        //     name: { 
        //         first: 'Shaoxiang', 
        //         last: 'Gao'
        //     } 
        // }        
    }
})

5. 更新文档

const couchdb = require('felix-couchdb')

const dbHost = '127.0.0.1'
const dbPort = 5984
const dbUser = 'root'
const dbPass = 'Q6$%xO0s'
const dbName = 'test'

const client = couchdb.createClient(dbHost, dbPort, dbUser, dbPass)

const db = client.db(dbName)

db.getDoc('Gao', function(err, doc){
    if(err){
        console.log(err)
    }else{
        doc.email = 'gsx0312@qq.com'
        //  更新文档使用的是与创建文档一样的saveDoc 命令
        //  如果CouchDB检测到有同样ID的记录存在
        // 它会把旧的记录覆盖
        db.saveDoc('Gao', doc)
        db.getDoc('Gao', function(err, revisedUser){
            console.log(revisedUser)
        })
    }
})

6. 删除文档

const couchdb = require('felix-couchdb')

const dbHost = '127.0.0.1'
const dbPort = 5984
const dbUser = 'root'
const dbPass = 'Q6$%xO0s'
const dbName = 'test'

const client = couchdb.createClient(dbHost, dbPort, dbUser, dbPass)

const db = client.db(dbName)

db.getDoc('Gao', function(err, doc){
    //  在CouchDB里删除文档
    //  需要同时提供ID和版本号
    db.removeDoc(doc._id, doc._rev)
})