Exemples CouchDB

Exemples de base de données NoSQL Apache CouchDB incluant les opérations de documents, les vues et la réplication

Key Facts

Category
Database
Items
3
Format Families
sql, json

Sample Overview

Exemples de base de données NoSQL Apache CouchDB incluant les opérations de documents, les vues et la réplication This sample set belongs to Database and can be used to test related workflows inside Elysia Tools.

💻 Opérations de Base CouchDB javascript

🟢 simple ⭐⭐

Opérations CRUD fondamentales avec les documents et bases de données CouchDB

⏱️ 20 min 🏷️ couchdb, nosql, document database, nodejs
Prerequisites: Basic JavaScript/Node.js, NoSQL concepts
// CouchDB Basic Operations
// JavaScript (Node.js) - Using nano library

const nano = require('nano')('http://localhost:5984');

// 1. Database Operations
class CouchDBManager {
    constructor(dbName) {
        this.dbName = dbName;
        this.db = nano.db.use(dbName);
    }

    // Create database
    async createDatabase() {
        try {
            await nano.db.create(this.dbName);
            console.log(`✅ Database '${this.dbName}' created successfully`);
            return true;
        } catch (error) {
            if (error.statusCode === 412) {
                console.log(`ℹ️ Database '${this.dbName}' already exists`);
            } else {
                console.error('❌ Error creating database:', error.message);
            }
            return false;
        }
    }

    // Delete database
    async deleteDatabase() {
        try {
            await nano.db.destroy(this.dbName);
            console.log(`✅ Database '${this.dbName}' deleted successfully`);
            return true;
        } catch (error) {
            console.error('❌ Error deleting database:', error.message);
            return false;
        }
    }

    // List all databases
    async listDatabases() {
        try {
            const databases = await nano.db.list();
            console.log('📊 Available databases:', databases);
            return databases;
        } catch (error) {
            console.error('❌ Error listing databases:', error.message);
            return [];
        }
    }

    // 2. Document Operations (CRUD)

    // Create document
    async createDocument(doc) {
        try {
            const response = await this.db.insert(doc);
            console.log(`✅ Document created with ID: ${response.id}, Rev: ${response.rev}`);
            return response;
        } catch (error) {
            console.error('❌ Error creating document:', error.message);
            throw error;
        }
    }

    // Read document by ID
    async getDocument(docId) {
        try {
            const doc = await this.db.get(docId);
            console.log(`📄 Retrieved document: ${JSON.stringify(doc, null, 2)}`);
            return doc;
        } catch (error) {
            if (error.statusCode === 404) {
                console.log(`⚠️ Document with ID '${docId}' not found`);
            } else {
                console.error('❌ Error getting document:', error.message);
            }
            return null;
        }
    }

    // Update document
    async updateDocument(docId, updatedDoc) {
        try {
            // First get the current document to get the _rev
            const currentDoc = await this.getDocument(docId);
            if (!currentDoc) {
                throw new Error('Document not found');
            }

            // Update the document with current _rev
            const docToUpdate = {
                ...updatedDoc,
                _id: docId,
                _rev: currentDoc._rev
            };

            const response = await this.db.insert(docToUpdate);
            console.log(`✅ Document updated with new Rev: ${response.rev}`);
            return response;
        } catch (error) {
            console.error('❌ Error updating document:', error.message);
            throw error;
        }
    }

    // Delete document
    async deleteDocument(docId) {
        try {
            const doc = await this.getDocument(docId);
            if (!doc) {
                throw new Error('Document not found');
            }

            const response = await this.db.destroy(docId, doc._rev);
            console.log(`✅ Document '${docId}' deleted successfully`);
            return response;
        } catch (error) {
            console.error('❌ Error deleting document:', error.message);
            throw error;
        }
    }

    // 3. Bulk Operations

    // Bulk create documents
    async bulkCreateDocuments(docs) {
        try {
            const response = await this.db.bulk({ docs });
            console.log(`✅ Bulk operation completed. ${response.filter(r => !r.error).length} documents created`);
            return response;
        } catch (error) {
            console.error('❌ Error in bulk create:', error.message);
            throw error;
        }
    }

    // 4. Query Operations

    // Get all documents
    async getAllDocuments() {
        try {
            const response = await this.db.list({ include_docs: true });
            console.log(`📋 Found ${response.total_rows} documents`);
            return response.rows.map(row => row.doc);
        } catch (error) {
            console.error('❌ Error getting all documents:', error.message);
            return [];
        }
    }

    // Query documents with Mango query
    async queryDocuments(selector, options = {}) {
        try {
            const response = await this.db.find({
                selector,
                ...options
            });
            console.log(`🔍 Query returned ${response.docs.length} documents`);
            return response.docs;
        } catch (error) {
            console.error('❌ Error querying documents:', error.message);
            return [];
        }
    }

    // 5. Document Design and Views
    async createDesignDocument(dDoc) {
        try {
            const response = await this.db.insert(dDoc);
            console.log(`✅ Design document created: ${response.id}`);
            return response;
        } catch (error) {
            console.error('❌ Error creating design document:', error.message);
            throw error;
        }
    }

    // Query view
    async queryView(dDocName, viewName, options = {}) {
        try {
            const response = await this.db.view(dDocName, viewName, options);
            console.log(`📊 View '${dDocName}/${viewName}' returned ${response.rows.length} results`);
            return response;
        } catch (error) {
            console.error('❌ Error querying view:', error.message);
            return null;
        }
    }
}

// Usage Examples
async function demonstrateCouchDB() {
    const dbManager = new CouchDBManager('example_db');

    // Create database
    await dbManager.createDatabase();

    // Create sample documents
    const userDoc = {
        type: 'user',
        name: 'John Doe',
        email: '[email protected]',
        age: 30,
        created_at: new Date().toISOString()
    };

    const productDoc = {
        type: 'product',
        name: 'Laptop',
        price: 999.99,
        category: 'Electronics',
        in_stock: true,
        created_at: new Date().toISOString()
    };

    // Create documents
    const userResult = await dbManager.createDocument(userDoc);
    const productResult = await dbManager.createDocument(productDoc);

    // Read documents
    await dbManager.getDocument(userResult.id);

    // Update document
    await dbManager.updateDocument(userResult.id, {
        ...userDoc,
        age: 31,
        last_updated: new Date().toISOString()
    });

    // Query with Mango
    const electronics = await dbManager.queryDocuments({
        type: 'product',
        category: 'Electronics'
    });

    console.log('Electronics products:', electronics);

    // Create design document with views
    const designDoc = {
        _id: '_design/products',
        views: {
            by_category: {
                map: function(doc) {
                    if (doc.type === 'product' && doc.category) {
                        emit(doc.category, doc.price);
                    }
                }.toString()
            },
            in_stock: {
                map: function(doc) {
                    if (doc.type === 'product' && doc.in_stock === true) {
                        emit(doc.name, null);
                    }
                }.toString()
            }
        }
    };

    await dbManager.createDesignDocument(designDoc);

    // Query views
    const categoryView = await dbManager.queryView('products', 'by_category', {
        group: true,
        reduce: true
    });

    console.log('Products by category:', categoryView);
}

// 6. Attachment Management
class CouchAttachmentManager extends CouchDBManager {
    // Add attachment to document
    async addAttachment(docId, attachmentName, attachmentData, contentType) {
        try {
            const doc = await this.getDocument(docId);
            const response = await this.db.attachment.insert(
                docId,
                attachmentName,
                attachmentData,
                contentType,
                doc._rev
            );
            console.log(`✅ Attachment '${attachmentName}' added to document '${docId}'`);
            return response;
        } catch (error) {
            console.error('❌ Error adding attachment:', error.message);
            throw error;
        }
    }

    // Get attachment
    async getAttachment(docId, attachmentName) {
        try {
            const response = await this.db.attachment.get(docId, attachmentName);
            console.log(`📎 Retrieved attachment '${attachmentName}' from document '${docId}'`);
            return response;
        } catch (error) {
            console.error('❌ Error getting attachment:', error.message);
            return null;
        }
    }

    // Delete attachment
    async deleteAttachment(docId, attachmentName) {
        try {
            const doc = await this.getDocument(docId);
            const response = await this.db.attachment.destroy(docId, attachmentName, doc._rev);
            console.log(`🗑️ Attachment '${attachmentName}' deleted from document '${docId}'`);
            return response;
        } catch (error) {
            console.error('❌ Error deleting attachment:', error.message);
            throw error;
        }
    }
}

// 7. Change Management
class CouchChangeTracker extends CouchDBManager {
    // Track changes since last update
    async trackChanges(since = 'now', options = {}) {
        try {
            const feed = this.db.follow({
                since,
                include_docs: true,
                ...options
            });

            feed.on('change', (change) => {
                console.log('📝 Change detected:', {
                    id: change.id,
                    seq: change.seq,
                    deleted: change.deleted,
                    changes: change.changes
                });

                if (change.doc) {
                    console.log('📄 Changed document:', change.doc);
                }
            });

            feed.on('error', (error) => {
                console.error('❌ Change tracking error:', error);
            });

            feed.follow();
            console.log('👂 Started tracking changes...');
            return feed;
        } catch (error) {
            console.error('❌ Error setting up change tracking:', error.message);
            return null;
        }
    }

    // Get changes once
    async getChanges(since = 0, options = {}) {
        try {
            const changes = await this.db.changes({
                since,
                include_docs: true,
                ...options
            });

            console.log(`📋 Found ${changes.results.length} changes`);
            return changes;
        } catch (error) {
            console.error('❌ Error getting changes:', error.message);
            return null;
        }
    }
}

// 8. Replication Management
class CouchReplicationManager {
    constructor() {
        this.nano = nano('http://localhost:5984');
    }

    // Setup replication
    async setupReplication(source, target, options = {}) {
        try {
            const replicationDoc = {
                _id: `replication_${Date.now()}`,
                source,
                target,
                create_target: options.createTarget || false,
                continuous: options.continuous || false,
                filter: options.filter,
                query_params: options.queryParams,
                doc_ids: options.docIds,
                ...options
            };

            const response = await this.nano.request({
                db: '_replicator',
                method: 'post',
                body: replicationDoc
            });

            console.log(`🔄 Replication setup initiated: ${response.id}`);
            return response;
        } catch (error) {
            console.error('❌ Error setting up replication:', error.message);
            throw error;
        }
    }

    // Monitor replication
    async getReplicationStatus(replicationId) {
        try {
            const replication = await this.nano.request({
                db: '_replicator',
                doc: replicationId
            });

            console.log(`📊 Replication status: ${replication.state}`, {
                source: replication.source,
                target: replication.target,
                state: replication.state,
                docs_read: replication.docs_read,
                docs_written: replication.docs_written,
                errors: replication.errors
            });

            return replication;
        } catch (error) {
            console.error('❌ Error getting replication status:', error.message);
            return null;
        }
    }
}

// Run the demonstration
if (require.main === module) {
    demonstrateCouchDB().catch(console.error);
}

module.exports = {
    CouchDBManager,
    CouchAttachmentManager,
    CouchChangeTracker,
    CouchReplicationManager
};

💻 Vues Map-Reduce CouchDB javascript

🟡 intermediate ⭐⭐⭐⭐

Création et utilisation de vues Map-Reduce pour l'agrégation et l'analyse de données

⏱️ 30 min 🏷️ couchdb, map-reduce, views, analytics, aggregation
Prerequisites: Basic CouchDB operations, JavaScript functions, Map-Reduce concepts
// CouchDB Map-Reduce Views
// JavaScript - Creating design documents with views and queries

const nano = require('nano')('http://localhost:5984');

class CouchViewManager {
    constructor(dbName) {
        this.db = nano.db.use(dbName);
    }

    // 1. Simple Map View
    async createSimpleMapViews() {
        const designDoc = {
            _id: '_design/simple',
            language: 'javascript',
            views: {
                // View to get all documents by type
                by_type: {
                    map: function(doc) {
                        if (doc.type) {
                            emit(doc.type, null);
                        }
                    }.toString()
                },

                // View to get all users by age
                users_by_age: {
                    map: function(doc) {
                        if (doc.type === 'user' && doc.age) {
                            emit(doc.age, doc.name);
                        }
                    }.toString()
                },

                // View to get products by price
                products_by_price: {
                    map: function(doc) {
                        if (doc.type === 'product' && doc.price) {
                            emit([doc.category, doc.price], doc);
                        }
                    }.toString()
                }
            }
        };

        const response = await this.db.insert(designDoc);
        console.log('✅ Simple views created:', response.id);
        return response;
    }

    // 2. Map-Reduce Views with Aggregation
    async createReduceViews() {
        const designDoc = {
            _id: '_design/analytics',
            language: 'javascript',
            views: {
                // Count documents by type
                count_by_type: {
                    map: function(doc) {
                        if (doc.type) {
                            emit(doc.type, 1);
                        }
                    }.toString(),
                    reduce: '_count'
                },

                // Sum prices by category
                total_price_by_category: {
                    map: function(doc) {
                        if (doc.type === 'product' && doc.category && doc.price) {
                            emit(doc.category, doc.price);
                        }
                    }.toString(),
                    reduce: '_sum'
                },

                // Average age by city
                avg_age_by_city: {
                    map: function(doc) {
                        if (doc.type === 'user' && doc.city && doc.age) {
                            emit(doc.city, doc.age);
                        }
                    }.toString(),
                    reduce: function(keys, values, rereduce) {
                        if (rereduce) {
                            // Re-reduce step
                            const totalSum = values.reduce((sum, item) => sum + item.sum, 0);
                            const totalCount = values.reduce((sum, item) => sum + item.count, 0);
                            return {
                                sum: totalSum,
                                count: totalCount,
                                avg: totalSum / totalCount
                            };
                        } else {
                            // First reduce step
                            const sum = values.reduce((a, b) => a + b, 0);
                            return {
                                sum: sum,
                                count: values.length,
                                avg: sum / values.length
                            };
                        }
                    }.toString()
                },

                // Statistics view with multiple reduce functions
                price_statistics: {
                    map: function(doc) {
                        if (doc.type === 'product' && doc.price) {
                            emit(doc.category, doc.price);
                        }
                    }.toString(),
                    reduce: function(keys, values, rereduce) {
                        if (rereduce) {
                            // Combine partial results
                            const allPrices = [];
                            values.forEach(item => {
                                if (item.prices) {
                                    allPrices.push(...item.prices);
                                }
                            });

                            return this.calculateStats(allPrices);
                        } else {
                            return this.calculateStats(values);
                        }
                    }.toString()
                }
            }
        };

        // Helper function for statistics
        designDoc.views.price_statistics.reduce = designDoc.views.price_statistics.reduce.replace(
            'this.calculateStats',
            `function(prices) {
                prices.sort((a, b) => a - b);
                const count = prices.length;
                const sum = prices.reduce((a, b) => a + b, 0);
                const mean = sum / count;
                const median = count % 2 === 0
                    ? (prices[count/2 - 1] + prices[count/2]) / 2
                    : prices[Math.floor(count/2)];

                return {
                    count: count,
                    sum: sum,
                    mean: mean,
                    median: median,
                    min: prices[0],
                    max: prices[count - 1],
                    prices: prices // Include for rereduce
                };
            }`
        );

const response = await this.db.insert(designDoc);
console.log('✅ Reduce views created:', response.id);
return response;
    }

    // 3. Complex Map Views
    async createComplexMapViews() {
    const designDoc = {
        _id: '_design/complex',
        language: 'javascript',
        views: {
            // View with compound keys
            users_by_city_and_age: {
                map: function (doc) {
                    if (doc.type === 'user' && doc.city && doc.age) {
                        emit([doc.city, Math.floor(doc.age / 10) * 10], {
                            name: doc.name,
                            age: doc.age,
                            email: doc.email
                        });
                    }
                }.toString()
            },

            // Time-series view
            activity_by_day: {
                map: function (doc) {
                    if (doc.created_at) {
                        var date = new Date(doc.created_at);
                        var dayKey = [date.getFullYear(), date.getMonth() + 1, date.getDate()];
                        emit(dayKey, {
                            type: doc.type,
                            hour: date.getHours()
                        });
                    }
                }.toString(),
                reduce: function (keys, values, rereduce) {
                    if (rereduce) {
                        return values.reduce((acc, curr) => {
                            Object.keys(curr).forEach(key => {
                                acc[key] = (acc[key] || 0) + curr[key];
                            });
                            return acc;
                        }, {});
                    } else {
                        const stats = {};
                        values.forEach(val => {
                            const type = val.type;
                            const hour = val.hour;

                            if (!stats[type]) stats[type] = { total: 0, hours: {} };
                            stats[type].total++;
                            stats[type].hours[hour] = (stats[type].hours[hour] || 0) + 1;
                        });
                        return stats;
                    }
                }.toString()
            },

            // View for full-text search (simple implementation)
            text_search: {
                map: function (doc) {
                    if (doc.type && doc.name) {
                        // Extract words from name and description
                        var text = doc.name + ' ' + (doc.description || '');
                        var words = text.toLowerCase().split(/\W+/);

                        words.forEach(function (word) {
                            if (word.length > 2) {
                                emit([word, doc.type], {
                                    id: doc._id,
                                    name: doc.name,
                                    type: doc.type
                                });
                            }
                        });
                    }
                }.toString()
            }
        }
    };

    const response = await this.db.insert(designDoc);
    console.log('✅ Complex views created:', response.id);
    return response;
}

    // 4. View Query Methods
    async queryView(dDocName, viewName, options = {}) {
    try {
        const response = await this.db.view(dDocName, viewName, options);
        return response;
    } catch (error) {
        console.error('❌ Error querying view:', error.message);
        throw error;
    }
}

    // Query examples
    async demonstrateQueries() {
    // Query users by specific age
    const users25to30 = await this.queryView('simple', 'users_by_age', {
        startkey: 25,
        endkey: 30,
        include_docs: true
    });

    console.log('Users aged 25-30:', users25to30.rows.length);

    // Query products by category range
    const electronics = await this.queryView('simple', 'products_by_price', {
        startkey: ['Electronics'],
        endkey: ['Electronics', {}],
        include_docs: true
    });

    console.log('Electronics products:', electronics.rows.length);

    // Get document counts by type
    const typeCounts = await this.queryView('analytics', 'count_by_type', {
        group: true
    });

    console.log('Document counts by type:');
    typeCounts.rows.forEach(row => {
        console.log(`  ${row.key}: ${row.value}`);
        });

        // Get total price by category
        const priceTotals = await this.queryView('analytics', 'total_price_by_category', {
            group: true
        });

        console.log('Total price by category:');
        priceTotals.rows.forEach(row => {
            console.log(`  ${row.key}: $${row.value.toFixed(2)}`);
        });

        // Get users by city and age groups
        const usersByCityAge = await this.queryView('complex', 'users_by_city_and_age', {
            group_level: 1,
            include_docs: true
        });

        console.log('Users by city:');
        usersByCityAge.rows.forEach(row => {
            console.log(`  ${row.key[0]}: ${row.value.length} users`);
        });
    }

    // 5. Advanced View Features
    async createAdvancedViews() {
        const designDoc = {
            _id: '_design/advanced',
            language: 'javascript',
            views: {
                // View with list function (using _list in URL)
                recent_activities: {
                    map: function(doc) {
                        if (doc.created_at && doc.type) {
                            emit(doc.created_at, {
                                _id: doc._id,
                                type: doc.type,
                                name: doc.name || doc.title || 'Unknown'
                            });
                        }
                    }.toString()
                },

                // View for filtering with built-in filters
                active_users: {
                    map: function(doc) {
                        if (doc.type === 'user' && doc.is_active !== false) {
                            emit(doc.email, {
                                name: doc.name,
                                last_login: doc.last_login,
                                created_at: doc.created_at
                            });
                        }
                    }.toString()
                },

                // View for relationship analysis
                user_connections: {
                    map: function(doc) {
                        if (doc.type === 'user' && doc.friends) {
                            doc.friends.forEach(function(friendId) {
                                emit([doc._id, friendId], {
                                    since: doc.friendship_since,
                                    strength: doc.friendship_strength || 1
                                });
                            });
                        }
                    }.toString(),
                    reduce: function(keys, values, rereduce) {
                        if (rereduce) {
                            return {
                                total_strength: values.reduce((sum, v) => sum + v.total_strength, 0),
                                count: values.reduce((sum, v) => sum + v.count, 0),
                                avg_strength: 0
                            };
                        } else {
                            const totalStrength = values.reduce((sum, v) => sum + v.strength, 0);
                            return {
                                total_strength: totalStrength,
                                count: values.length,
                                avg_strength: totalStrength / values.length
                            };
                        }
                    }.toString()
                }
            },
            // List functions for formatting output
            lists: {
                recent_activities_json: function(head, req) {
                    provides('json', function() {
                        var results = [];
                        while (row = getRow()) {
                            results.push({
                                id: row.value._id,
                                type: row.value.type,
                                name: row.value.name,
                                timestamp: row.key
                            });
                        }
                        send(JSON.stringify({
                            total_rows: head.total_rows,
                            offset: head.offset,
                            activities: results
                        }));
                    });
                }.toString()
            },
            // Show functions for document formatting
            shows: {
                user_profile: function(doc, req) {
                    if (doc.type === 'user') {
                        return {
                            html: '<h1>' + doc.name + '</h1>' +
                                  '<p>Email: ' + doc.email + '</p>' +
                                  '<p>Age: ' + doc.age + '</p>' +
                                  '<p>City: ' + doc.city + '</p>'
                        };
                    }
                    return null;
                }.toString()
            }
        };

        const response = await this.db.insert(designDoc);
        console.log('✅ Advanced views created:', response.id);
        return response;
    }

    // 6. View Performance Optimization
    async optimizeViews() {
        const designDoc = {
            _id: '_design/optimized',
            language: 'javascript',
            views: {
                // Efficient view with proper key design
                orders_by_date: {
                    map: function(doc) {
                        if (doc.type === 'order' && doc.date) {
                            // Emit date in ISO format for proper sorting
                            emit([doc.customer_id, doc.date], {
                                order_id: doc._id,
                                total: doc.total,
                                items: doc.items.length
                            });
                        }
                    }.toString()
                },

                // View with selective indexing
                indexed_products: {
                    map: function(doc) {
                        // Only index documents we actually need to query
                        if (doc.type === 'product' &&
                            doc.status === 'active' &&
                            doc.price > 0) {
                            emit(doc.category, {
                                id: doc._id,
                                name: doc.name,
                                price: doc.price,
                                rating: doc.rating || 0
                            });
                        }
                    }.toString()
                }
            },
            options: {
                // Automatic view indexing
                // Changes will automatically update views
            }
        };

        const response = await this.db.insert(designDoc);
        console.log('✅ Optimized views created:', response.id);
        return response;
    }
}

// Usage Example
async function demonstrateViews() {
    const viewManager = new CouchViewManager('analytics_db');

    // Create different types of views
    await viewManager.createSimpleMapViews();
    await viewManager.createReduceViews();
    await viewManager.createComplexMapViews();
    await viewManager.createAdvancedViews();
    await viewManager.optimizeViews();

    // Demonstrate queries
    await viewManager.demonstrateQueries();
}

if (require.main === module) {
    demonstrateViews().catch(console.error);
}

module.exports = CouchViewManager;

💻 Réplication et Synchronisation CouchDB javascript

🔴 complex ⭐⭐⭐⭐

Configuration de la réplication, résolution de conflits et synchronisation des données

⏱️ 35 min 🏷️ couchdb, replication, sync, distributed systems, conflict resolution
Prerequisites: Advanced CouchDB operations, Network concepts, Conflict resolution strategies
// CouchDB Replication and Synchronization
// JavaScript - Advanced replication patterns and conflict resolution

const nano = require('nano')('http://localhost:5984');

class CouchReplicationManager {
    constructor() {
        this.nano = nano;
        this.replications = new Map();
    }

    // 1. Basic Replication Setup
    async setupOneTimeReplication(source, target, options = {}) {
        const replicationDoc = {
            _id: `replication_${Date.now()}`,
            source: source,
            target: target,
            create_target: options.createTarget || false,
            continuous: false,
            // Filter documents if needed
            filter: options.filter,
            query_params: options.queryParams,
            doc_ids: options.docIds
        };

        try {
            const response = await this.nano.request({
                db: '_replicator',
                method: 'post',
                body: replicationDoc
            });

            console.log(`✅ One-time replication started: ${response.id}`);
            this.replications.set(response.id, replicationDoc);
            return response;
        } catch (error) {
            console.error('❌ Error setting up one-time replication:', error.message);
            throw error;
        }
    }

    // 2. Continuous Replication
    async setupContinuousReplication(source, target, options = {}) {
        const replicationDoc = {
            _id: `continuous_${Date.now()}`,
            source: source,
            target: target,
            create_target: options.createTarget || false,
            continuous: true,
            // Replication options
            filter: options.filter,
            query_params: options.queryParams,
            doc_ids: options.docIds,
            // Heartbeat configuration
            heartbeat: options.heartbeat || 30000,
            // Worker processes
            worker_processes: options.workerProcesses || 1,
            // Batch size
            worker_batch_size: options.batchSize || 500,
            // Connection timeout
            timeout: options.timeout || 30000
        };

        try {
            const response = await this.nano.request({
                db: '_replicator',
                method: 'post',
                body: replicationDoc
            });

            console.log(`🔄 Continuous replication started: ${response.id}`);
            this.replications.set(response.id, replicationDoc);

            // Start monitoring
            this.monitorReplication(response.id);

            return response;
        } catch (error) {
            console.error('❌ Error setting up continuous replication:', error.message);
            throw error;
        }
    }

    // 3. Bi-directional Sync
    async setupBiDirectionalSync(db1, db2, options = {}) {
        const syncOptions = {
            ...options,
            continuous: true,
            create_target: false
        };

        // Replicate db1 -> db2
        const rep1 = await this.setupContinuousReplication(db1, db2, {
            ...syncOptions,
            _id: `sync_${db1}_to_${db2}_${Date.now()}`
        });

        // Replicate db2 -> db1
        const rep2 = await this.setupContinuousReplication(db2, db1, {
            ...syncOptions,
            _id: `sync_${db2}_to_${db1}_${Date.now()}`
        });

        console.log(`🔄 Bi-directional sync established between ${db1} and ${db2}`);

        return {
            forward: rep1,
            backward: rep2
        };
    }

    // 4. Filtered Replication
    async setupFilteredReplication(source, target, filterConfig) {
        // Create filter function in design document
        const filterDesignDoc = {
            _id: '_design/filters',
            filters: {
                by_type: function(doc, req) {
                    // Only replicate certain document types
                    const allowedTypes = req.query.types ?
                        req.query.types.split(',') :
                        ['user', 'product'];

                    return allowedTypes.includes(doc.type);
                }.toString(),

                by_date: function(doc, req) {
                    // Only replicate documents after certain date
                    if (!doc.created_at) return false;

                    const sinceDate = req.query.since || '1970-01-01';
                    const docDate = new Date(doc.created_at);
                    const filterDate = new Date(sinceDate);

                    return docDate >= filterDate;
                }.toString(),

                by_user: function(doc, req) {
                    // Only replicate user-specific data
                    if (doc.type === 'user') {
                        return doc._id === req.query.userId;
                    }
                    if (doc.owner) {
                        return doc.owner === req.query.userId;
                    }
                    if (doc.shared_with && doc.shared_with.includes(req.query.userId)) {
                        return true;
                    }
                    return false;
                }.toString()
            }
        };

        try {
            // Save filter design document
            const sourceDb = this.nano.db.use(source);
            await sourceDb.insert(filterDesignDoc);

            // Setup replication with filter
            return await this.setupContinuousReplication(source, target, {
                filter: 'filters/by_' + filterConfig.type,
                query_params: filterConfig.params
            });

        } catch (error) {
            console.error('❌ Error setting up filtered replication:', error.message);
            throw error;
        }
    }

    // 5. Replication Monitoring
    async monitorReplication(replicationId) {
        const checkInterval = 5000; // Check every 5 seconds

        const monitor = setInterval(async () => {
            try {
                const status = await this.getReplicationStatus(replicationId);

                if (status) {
                    console.log(`📊 Replication ${replicationId} status: ${status.state}`, {
                        docs_read: status.docs_read || 0,
                        docs_written: status.docs_written || 0,
                        errors: status.errors || 0,
                        progress: status.progress || 0
                    });

                    // Stop monitoring if replication completes
                    if (status.state === 'completed' || status.state === 'error') {
                        clearInterval(monitor);
                        console.log(`🏁 Replication ${replicationId} finished with status: ${status.state}`);
                    }
                }
            } catch (error) {
                console.error('❌ Error monitoring replication:', error.message);
                clearInterval(monitor);
            }
        }, checkInterval);
    }

    // Get replication status
    async getReplicationStatus(replicationId) {
        try {
            const replication = await this.nano.request({
                db: '_replicator',
                doc: replicationId
            });

            return replication;
        } catch (error) {
            if (error.statusCode === 404) {
                console.log(`⚠️ Replication ${replicationId} not found`);
            } else {
                console.error('❌ Error getting replication status:', error.message);
            }
            return null;
        }
    }

    // 6. Conflict Resolution
    async resolveConflicts(dbName, conflictResolver) {
        const db = this.nano.db.use(dbName);

        // Get all documents with conflicts
        const conflicts = await db.view('_docs_with_conflicts', 'conflicts', {
            include_docs: true
        });

        console.log(`⚠️ Found ${conflicts.rows.length} documents with conflicts`);

        for (const row of conflicts.rows) {
            const doc = row.doc;
            const conflictingRevs = doc._conflicts;

            if (conflictingRevs && conflictingRevs.length > 0) {
                console.log(`🔄 Resolving conflicts for document: ${doc._id}`);

                // Get all conflicting revisions
                const revisions = [];
                for (const rev of conflictingRevs) {
                    try {
                        const conflictDoc = await db.get(doc._id, { rev: rev });
                        revisions.push(conflictDoc);
                    } catch (error) {
                        console.error(`❌ Error getting revision ${rev}:`, error.message);
                    }
                }

                // Use custom conflict resolver
                const resolvedDoc = await conflictResolver(doc, revisions);

                if (resolvedDoc) {
                    // Save resolved document
                    try {
                        const response = await db.insert(resolvedDoc);
                        console.log(`✅ Conflict resolved for ${doc._id}: ${response.rev}`);
                    } catch (error) {
                        console.error(`❌ Error saving resolved document ${doc._id}:`, error.message);
                    }
                }
            }
        }
    }

    // Default conflict resolution strategies
    static conflictResolvers = {
        // Use most recent document based on timestamp
        latestWins: async (currentDoc, conflicts) => {
            let latestDoc = currentDoc;
            let latestTime = new Date(currentDoc.updated_at || currentDoc.created_at || 0);

            for (const conflict of conflicts) {
                const conflictTime = new Date(conflict.updated_at || conflict.created_at || 0);
                if (conflictTime > latestTime) {
                    latestTime = conflictTime;
                    latestDoc = conflict;
                }
            }

            // Clean up conflicts
            delete latestDoc._conflicts;
            return latestDoc;
        },

        // Merge documents (for specific types)
        merge: async (currentDoc, conflicts) => {
            // Simple merge strategy
            const merged = { ...currentDoc };

            for (const conflict of conflicts) {
                // Merge properties from conflicts
                Object.keys(conflict).forEach(key => {
                    if (key !== '_id' && key !== '_rev' && key !== '_conflicts') {
                        if (!merged[key] ||
                            (conflict.updated_at && (!merged.updated_at || new Date(conflict.updated_at) > new Date(merged.updated_at)))) {
                            merged[key] = conflict[key];
                        }
                    }
                });
            }

            delete merged._conflicts;
            return merged;
        },

        // Keep document with highest version number
        versionBased: async (currentDoc, conflicts) => {
            let versionDoc = currentDoc;
            let highestVersion = parseInt(currentDoc.version || '1');

            for (const conflict of conflicts) {
                const conflictVersion = parseInt(conflict.version || '1');
                if (conflictVersion > highestVersion) {
                    highestVersion = conflictVersion;
                    versionDoc = conflict;
                }
            }

            delete versionDoc._conflicts;
            versionDoc.version = (highestVersion + 1).toString();
            return versionDoc;
        }
    };

    // 7. Sync Status Management
    async getSyncStatus(sourceDb, targetDb) {
        try {
            // Get info from both databases
            const sourceInfo = await this.nano.db.info(sourceDb);
            const targetInfo = await this.nano.db.info(targetDb);

            // Get replication tasks
            const activeTasks = await this.nano.request({
                path: '_active_tasks',
                method: 'get'
            });

            const replications = activeTasks.filter(task =>
                task.type === 'replication' &&
                (task.source === sourceDb || task.target === targetDb)
            );

            return {
                source: {
                    name: sourceDb,
                    doc_count: sourceInfo.doc_count,
                    update_seq: sourceInfo.update_seq
                },
                target: {
                    name: targetDb,
                    doc_count: targetInfo.doc_count,
                    update_seq: targetInfo.update_seq
                },
                active_replications: replications.map(rep => ({
                    task_id: rep.task_id,
                    source: rep.source,
                    target: rep.target,
                    state: rep.state,
                    progress: rep.progress,
                    docs_read: rep.docs_read,
                    docs_written: rep.docs_written
                }))
            };
        } catch (error) {
            console.error('❌ Error getting sync status:', error.message);
            return null;
        }
    }

    // 8. Backup and Restore with Replication
    async setupBackupReplication(sourceDb, backupDb, options = {}) {
        const backupOptions = {
            ...options,
            continuous: options.continuousBackup || false,
            create_target: true,
            // Backup filter
            filter: function(doc) {
                // Don't replicate temporary or design documents unless specified
                if (doc._id && doc._id.startsWith('_temp/')) return false;
                if (doc._id && doc._id.startsWith('_design/') && !options.includeDesignDocs) return false;
                return true;
            }.toString(),
            query_params: {
                include_design_docs: options.includeDesignDocs || false
            }
        };

        return await this.setupContinuousReplication(sourceDb, backupDb, backupOptions);
    }

    // 9. Cleanup and Maintenance
    async cleanupReplication(replicationId) {
        try {
            // Stop the replication
            await this.nano.request({
                db: '_replicator',
                doc: replicationId,
                method: 'delete'
            });

            this.replications.delete(replicationId);
            console.log(`🗑️ Replication ${replicationId} stopped and cleaned up`);

            return true;
        } catch (error) {
            console.error('❌ Error cleaning up replication:', error.message);
            return false;
        }
    }

    // Cleanup old replications
    async cleanupOldReplications(maxAge = 24 * 60 * 60 * 1000) { // Default 24 hours
        try {
            const replications = await this.nano.request({
                db: '_replicator',
                method: 'get'
            });

            const now = Date.now();
            const oldReplications = [];

            for (const rep of replications.rows) {
                const repDoc = rep.doc;
                const timestamp = parseInt(repDoc._id.split('_').pop());

                if (now - timestamp > maxAge) {
                    oldReplications.push(repDoc._id);
                }
            }

            // Delete old replications
            for (const repId of oldReplications) {
                await this.cleanupReplication(repId);
            }

            console.log(`🗑️ Cleaned up ${oldReplications.length} old replications`);

            return oldReplications.length;
        } catch (error) {
            console.error('❌ Error cleaning up old replications:', error.message);
            return 0;
        }
    }
}

// Usage Example
async function demonstrateReplication() {
    const repManager = new CouchReplicationManager();

    // Setup one-time replication
    await repManager.setupOneTimeReplication('source_db', 'backup_db', {
        createTarget: true
    });

    // Setup continuous replication
    await repManager.setupContinuousReplication('source_db', 'replica_db', {
        createTarget: true
    });

    // Setup bi-directional sync
    await repManager.setupBiDirectionalSync('db1', 'db2');

    // Setup filtered replication
    await repManager.setupFilteredReplication('source_db', 'filtered_replica', {
        type: 'by_user',
        params: { userId: 'user123' }
    });

    // Resolve conflicts
    await repManager.resolveConflicts('sync_db', CouchReplicationManager.conflictResolvers.latestWins);

    // Get sync status
    const syncStatus = await repManager.getSyncStatus('source_db', 'replica_db');
    console.log('Sync status:', JSON.stringify(syncStatus, null, 2));

    // Setup backup replication
    await repManager.setupBackupReplication('production_db', 'backup_db', {
        continuousBackup: true,
        includeDesignDocs: true
    });
}

if (require.main === module) {
    demonstrateReplication().catch(console.error);
}

module.exports = CouchReplicationManager;