データベース
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 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": "開発部"
},
"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