Database

CouchDB

Overview

Apache CouchDB, standing for "Cluster Of Unreliable Commodity Hardware DataBase," is a distributed document-oriented NoSQL database. It stores data in JSON format and provides access through HTTP/RESTful APIs. With multi-master replication capabilities, it excels in offline operation and synchronization, enabling the construction of reliable database systems.

Details

CouchDB was developed by Damien Katz in 2005 and is now part of the Apache Software Foundation. Built with an "Offline First" design philosophy, it ensures stable data management even in environments with unstable network connections. It provides a MapReduce view system and JavaScript-based query functionality.

Key features of CouchDB:

  • Document-oriented database (JSON)
  • HTTP/RESTful API
  • Multi-master replication
  • MVCC (Multi-Version Concurrency Control)
  • MapReduce view system
  • JavaScript query engine
  • Offline operation support
  • Distributed architecture
  • Eventual consistency
  • Conflict resolution

Advantages and Disadvantages

Advantages

  • HTTP API: Accessible via standard HTTP protocol
  • Replication: Powerful distribution and synchronization features
  • Offline support: Continues operation when network is disconnected
  • Schema-free: Flexible document structure
  • Web-based management: Intuitive management interface with Fauxton
  • Language independent: Usable from any language via HTTP API
  • Conflict resolution: Automatic resolution of conflict states

Disadvantages

  • Query limitations: Complex SQL-like queries are difficult
  • Performance: May not be suitable for high-speed processing of large data
  • View updates: MapReduce view updates can be costly
  • Transactions: Limited ACID properties
  • Learning curve: Different design philosophy from traditional RDBMS

Key Links

Code Examples

Installation & Setup

# Ubuntu/Debian
sudo apt update
sudo apt install couchdb

# Red Hat/CentOS
sudo yum install epel-release
sudo yum install couchdb

# macOS (Homebrew)
brew install couchdb

# Docker
docker run -d --name couchdb-container \
  -e COUCHDB_USER=admin \
  -e COUCHDB_PASSWORD=password \
  -p 5984:5984 \
  couchdb:latest

# Start CouchDB
sudo systemctl start couchdb
sudo systemctl enable couchdb

# Web access
# http://localhost:5984
# http://localhost:5984/_utils (Fauxton UI)

Basic Operations (CRUD)

# Create Database
curl -X PUT http://admin:password@localhost:5984/mydb

# Create Document
curl -X POST http://admin:password@localhost:5984/mydb \
  -H "Content-Type: application/json" \
  -d '{
    "name": "John Doe",
    "age": 30,
    "email": "[email protected]",
    "department": "Engineering",
    "skills": ["JavaScript", "Python", "CouchDB"]
  }'

# Create Document with specific ID
curl -X PUT http://admin:password@localhost:5984/mydb/user001 \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Jane Smith",
    "age": 28,
    "email": "[email protected]",
    "department": "Sales"
  }'

# Read Document
curl -X GET http://admin:password@localhost:5984/mydb/user001

# Get all documents in database
curl -X GET http://admin:password@localhost:5984/mydb/_all_docs

# Update Document
# First get current revision
REV=$(curl -s http://admin:password@localhost:5984/mydb/user001 | jq -r '._rev')

curl -X PUT http://admin:password@localhost:5984/mydb/user001 \
  -H "Content-Type: application/json" \
  -d "{
    \"_rev\": \"$REV\",
    \"name\": \"Jane Smith\",
    \"age\": 29,
    \"email\": \"[email protected]\",
    \"department\": \"Sales\",
    \"promotion\": \"Manager\"
  }"

# Delete Document
REV=$(curl -s http://admin:password@localhost:5984/mydb/user001 | jq -r '._rev')
curl -X DELETE "http://admin:password@localhost:5984/mydb/user001?rev=$REV"

Database Management

# List all databases
curl -X GET http://admin:password@localhost:5984/_all_dbs

# Get database information
curl -X GET http://admin:password@localhost:5984/mydb

# Delete database
curl -X DELETE http://admin:password@localhost:5984/mydb

# Bulk operations (multiple documents at once)
curl -X POST http://admin:password@localhost:5984/mydb/_bulk_docs \
  -H "Content-Type: application/json" \
  -d '{
    "docs": [
      {
        "name": "Bob Wilson",
        "age": 25,
        "email": "[email protected]"
      },
      {
        "name": "Alice Brown",
        "age": 32,
        "email": "[email protected]"
      }
    ]
  }'

Views and Queries

// Create MapReduce views
curl -X PUT http://admin:password@localhost:5984/mydb/_design/users \
  -H "Content-Type: application/json" \
  -d '{
    "_id": "_design/users",
    "views": {
      "by_age": {
        "map": "function(doc) { if(doc.age) { emit(doc.age, doc.name); } }"
      },
      "by_department": {
        "map": "function(doc) { if(doc.department) { emit(doc.department, [doc.name, doc.age]); } }"
      },
      "age_stats": {
        "map": "function(doc) { if(doc.age) { emit(doc.department, doc.age); } }",
        "reduce": "function(keys, values) { return Math.round(values.reduce(function(a,b) { return a + b; }) / values.length); }"
      }
    }
  }'

# Query views
# Sort by age
curl -X GET "http://admin:password@localhost:5984/mydb/_design/users/_view/by_age"

# Specific age range
curl -X GET "http://admin:password@localhost:5984/mydb/_design/users/_view/by_age?startkey=25&endkey=35"

# Group by department
curl -X GET "http://admin:password@localhost:5984/mydb/_design/users/_view/by_department?group=true"

# Mango Query (CouchDB 2.0+)
curl -X POST http://admin:password@localhost:5984/mydb/_find \
  -H "Content-Type: application/json" \
  -d '{
    "selector": {
      "age": {"$gt": 25},
      "department": "Engineering"
    },
    "fields": ["name", "age", "email"],
    "sort": [{"age": "asc"}]
  }'

Replication

# One-time replication
curl -X POST http://admin:password@localhost:5984/_replicate \
  -H "Content-Type: application/json" \
  -d '{
    "source": "mydb",
    "target": "mydb_backup",
    "create_target": true
  }'

# Continuous replication setup
curl -X PUT http://admin:password@localhost:5984/_replicator/continuous_sync \
  -H "Content-Type: application/json" \
  -d '{
    "_id": "continuous_sync",
    "source": "mydb",
    "target": "http://remote-server:5984/mydb",
    "continuous": true,
    "create_target": true
  }'

# Remote server replication
curl -X POST http://admin:password@localhost:5984/_replicate \
  -H "Content-Type: application/json" \
  -d '{
    "source": "http://localhost:5984/mydb",
    "target": "http://admin:password@remote-server:5984/mydb",
    "continuous": true,
    "create_target": true
  }'

# Check replication status
curl -X GET http://admin:password@localhost:5984/_active_tasks

# Manage replication jobs
curl -X GET http://admin:password@localhost:5984/_scheduler/jobs

Practical Examples

# Create index (for Mango Query)
curl -X POST http://admin:password@localhost:5984/mydb/_index \
  -H "Content-Type: application/json" \
  -d '{
    "index": {
      "fields": ["department", "age"]
    },
    "name": "dept-age-index",
    "type": "json"
  }'

# Store attachment
curl -X PUT http://admin:password@localhost:5984/mydb/user001/avatar.jpg?rev=$REV \
  -H "Content-Type: image/jpeg" \
  --data-binary @avatar.jpg

# Retrieve attachment
curl -X GET http://admin:password@localhost:5984/mydb/user001/avatar.jpg \
  -o downloaded_avatar.jpg

# Compact database
curl -X POST http://admin:password@localhost:5984/mydb/_compact

# Compact view
curl -X POST http://admin:password@localhost:5984/mydb/_compact/users

JavaScript Client Example

// Node.js CouchDB library (nano)
const nano = require('nano')('http://admin:password@localhost:5984')
const db = nano.db.use('mydb')

// Create document
async function createUser() {
  try {
    const response = await db.insert({
      name: 'John Doe',
      age: 30,
      email: '[email protected]',
      department: 'Engineering'
    })
    console.log('User created:', response)
  } catch (error) {
    console.error('Error creating user:', error)
  }
}

// Get document
async function getUser(id) {
  try {
    const user = await db.get(id)
    console.log('User found:', user)
    return user
  } catch (error) {
    console.error('Error getting user:', error)
  }
}

// Update document
async function updateUser(id, updates) {
  try {
    const user = await db.get(id)
    const updatedUser = { ...user, ...updates }
    const response = await db.insert(updatedUser)
    console.log('User updated:', response)
  } catch (error) {
    console.error('Error updating user:', error)
  }
}

// View query
async function getUsersByDepartment(department) {
  try {
    const result = await db.view('users', 'by_department', {
      key: department,
      include_docs: true
    })
    return result.rows.map(row => row.doc)
  } catch (error) {
    console.error('Error querying view:', error)
  }
}

// Usage examples
createUser()
updateUser('user001', { age: 31, promotion: 'Manager' })
getUsersByDepartment('Engineering').then(users => console.log(users))

Configuration and Security

# Create admin user
curl -X PUT http://localhost:5984/_config/admins/admin -d '"password"'

# CORS settings
curl -X PUT http://admin:password@localhost:5984/_config/httpd/enable_cors -d '"true"'
curl -X PUT http://admin:password@localhost:5984/_config/cors/origins -d '"*"'

# Check SSL configuration
curl -X GET http://admin:password@localhost:5984/_config/ssl

# Database security settings
curl -X PUT http://admin:password@localhost:5984/mydb/_security \
  -H "Content-Type: application/json" \
  -d '{
    "admins": {
      "names": ["admin"],
      "roles": ["admin"]
    },
    "members": {
      "names": ["user1", "user2"],
      "roles": ["member"]
    }
  }'

# Get configuration
curl -X GET http://admin:password@localhost:5984/_config

Performance Monitoring

# System statistics
curl -X GET http://admin:password@localhost:5984/_stats

# Check active tasks
curl -X GET http://admin:password@localhost:5984/_active_tasks

# Membership information (cluster environment)
curl -X GET http://admin:password@localhost:5984/_membership

# Check logs
curl -X GET http://admin:password@localhost:5984/_log

# Detailed database information
curl -X GET http://admin:password@localhost:5984/mydb/_stats