データベース

CouchDB

概要

Apache CouchDBは、「Cluster Of Unreliable Commodity Hardware DataBase」の略で、分散型ドキュメント指向NoSQLデータベースです。JSON形式でデータを保存し、HTTP/RESTful APIを通じてアクセスできます。多重マスターレプリケーション機能により、オフライン動作と同期に優れており、信頼性の高いデータベースシステムを構築できます。

詳細

CouchDBは2005年にDamien Katzによって開発され、現在はApache Software Foundationの一部となっています。「Offline First」の設計思想で作られており、ネットワーク接続が不安定な環境でも安定したデータ管理を実現します。MapReduceによるビューシステムとJavaScriptベースのクエリ機能を提供しています。

CouchDBの主な特徴:

  • ドキュメント指向データベース(JSON)
  • HTTP/RESTful API
  • 多重マスターレプリケーション
  • MVCC(Multi-Version Concurrency Control)
  • MapReduceビューシステム
  • JavaScriptクエリエンジン
  • オフライン動作対応
  • 分散アーキテクチャ
  • 最終的整合性
  • コンフリクト解決機能

メリット・デメリット

メリット

  • HTTP API: 標準的なHTTPプロトコルでアクセス可能
  • レプリケーション: 強力な分散・同期機能
  • オフライン対応: ネットワーク切断時も動作継続
  • Schema-free: 柔軟なドキュメント構造
  • Webベース管理: Futonによる直感的な管理インターフェース
  • 言語非依存: HTTP APIによりあらゆる言語から利用可能
  • コンフリクト解決: 自動的な競合状態の解決

デメリット

  • クエリ制限: SQLライクな複雑クエリが困難
  • パフォーマンス: 大量データの高速処理には向かない場合
  • ビューの更新: MapReduceビューの更新にコストがかかる
  • トランザクション: ACID特性が限定的
  • 学習コスト: 従来のRDBMSと異なる設計思想

主要リンク

書き方の例

インストール・セットアップ

# 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

# CouchDB起動
sudo systemctl start couchdb
sudo systemctl enable couchdb

# Webアクセス
# http://localhost:5984
# http://localhost:5984/_utils (Fauxton UI)

基本操作(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": "田中太郎",
    "age": 30,
    "email": "[email protected]",
    "department": "開発部",
    "skills": ["JavaScript", "Python", "CouchDB"]
  }'

# 特定IDでドキュメント作成
curl -X PUT http://admin:password@localhost:5984/mydb/user001 \
  -H "Content-Type: application/json" \
  -d '{
    "name": "佐藤花子",
    "age": 28,
    "email": "[email protected]",
    "department": "営業部"
  }'

# ドキュメント読み取り(Read Document)
curl -X GET http://admin:password@localhost:5984/mydb/user001

# データベース内全ドキュメント取得
curl -X GET http://admin:password@localhost:5984/mydb/_all_docs

# ドキュメント更新(Update Document)
# まず現在の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\": \"佐藤花子\",
    \"age\": 29,
    \"email\": \"[email protected]\",
    \"department\": \"営業部\",
    \"promotion\": \"主任\"
  }"

# ドキュメント削除(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"

データベース管理

# データベース一覧
curl -X GET http://admin:password@localhost:5984/_all_dbs

# データベース情報取得
curl -X GET http://admin:password@localhost:5984/mydb

# データベース削除
curl -X DELETE http://admin:password@localhost:5984/mydb

# バルク操作(複数ドキュメント一括操作)
curl -X POST http://admin:password@localhost:5984/mydb/_bulk_docs \
  -H "Content-Type: application/json" \
  -d '{
    "docs": [
      {
        "name": "山田次郎",
        "age": 25,
        "email": "[email protected]"
      },
      {
        "name": "鈴木一郎",
        "age": 32,
        "email": "[email protected]"
      }
    ]
  }'

ビューとクエリ

// MapReduceビューの作成
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); }"
      }
    }
  }'

# ビューによるクエリ実行
# 年齢でソート
curl -X GET "http://admin:password@localhost:5984/mydb/_design/users/_view/by_age"

# 特定の年齢範囲
curl -X GET "http://admin:password@localhost:5984/mydb/_design/users/_view/by_age?startkey=25&endkey=35"

# 部署別グループ化
curl -X GET "http://admin:password@localhost:5984/mydb/_design/users/_view/by_department?group=true"

# Mango QueryCouchDB 2.0以降)
curl -X POST http://admin:password@localhost:5984/mydb/_find \
  -H "Content-Type: application/json" \
  -d '{
    "selector": {
      "age": {"$gt": 25},
      "department": "開発部"
    },
    "fields": ["name", "age", "email"],
    "sort": [{"age": "asc"}]
  }'

レプリケーション

# 一回限りのレプリケーション
curl -X POST http://admin:password@localhost:5984/_replicate \
  -H "Content-Type: application/json" \
  -d '{
    "source": "mydb",
    "target": "mydb_backup",
    "create_target": true
  }'

# 継続的レプリケーション設定
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
  }'

# リモートサーバーとのレプリケーション
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
  }'

# レプリケーション状況確認
curl -X GET http://admin:password@localhost:5984/_active_tasks

# レプリケーションジョブ管理
curl -X GET http://admin:password@localhost:5984/_scheduler/jobs

実用例

# インデックス作成(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"
  }'

# 添付ファイルの保存
curl -X PUT http://admin:password@localhost:5984/mydb/user001/avatar.jpg?rev=$REV \
  -H "Content-Type: image/jpeg" \
  --data-binary @avatar.jpg

# 添付ファイルの取得
curl -X GET http://admin:password@localhost:5984/mydb/user001/avatar.jpg \
  -o downloaded_avatar.jpg

# データベース圧縮
curl -X POST http://admin:password@localhost:5984/mydb/_compact

# ビューの圧縮
curl -X POST http://admin:password@localhost:5984/mydb/_compact/users

JavaScriptクライアント例

// Node.js用のCouchDBライブラリ(nano)
const nano = require('nano')('http://admin:password@localhost:5984')
const db = nano.db.use('mydb')

// ドキュメント作成
async function createUser() {
  try {
    const response = await db.insert({
      name: '田中太郎',
      age: 30,
      email: '[email protected]',
      department: '開発部'
    })
    console.log('User created:', response)
  } catch (error) {
    console.error('Error creating user:', error)
  }
}

// ドキュメント取得
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)
  }
}

// ドキュメント更新
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)
  }
}

// ビュークエリ
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)
  }
}

// 使用例
createUser()
updateUser('user001', { age: 31, promotion: '主任' })
getUsersByDepartment('開発部').then(users => console.log(users))

設定とセキュリティ

# 管理者作成
curl -X PUT http://localhost:5984/_config/admins/admin -d '"password"'

# CORS設定
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 '"*"'

# SSL設定確認
curl -X GET http://admin:password@localhost:5984/_config/ssl

# データベースのセキュリティ設定
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"]
    }
  }'

# 設定情報の取得
curl -X GET http://admin:password@localhost:5984/_config

パフォーマンス監視

# システム統計
curl -X GET http://admin:password@localhost:5984/_stats

# アクティブタスク確認
curl -X GET http://admin:password@localhost:5984/_active_tasks

# メンバーシップ情報(クラスター環境)
curl -X GET http://admin:password@localhost:5984/_membership

# ログ確認
curl -X GET http://admin:password@localhost:5984/_log

# データベース情報詳細
curl -X GET http://admin:password@localhost:5984/mydb/_stats