Search code examples
node.jsexpresspouchdb

How can I create separate PouchDBs on separate endpoints in the same Node app, living in separate databases on disk?


Express-pouchdb, part of Pouchdb-server, is a "fully qualified Express application" that creates a mostly-CouchDB-compliant database in Node that allows browser-based PouchDB instances to sync to it.

My goal is to have Node create multiple separate PouchDBs, on separate endpoints, that store their data in totally different paths on disk.

After running npm install express-pouchdb pouchdb express, I start with the snippet from the docs: one endpoint, one PouchDB—

var PouchDB = require('pouchdb');
var express = require('express');
var app = express();

app.use('/db1', require('express-pouchdb')(PouchDB));
app.listen(3000);

This of course works fine.

However, adapting this to add a second endpoint fails:

// same setup as above
app.use('/db1', require('express-pouchdb')(PouchDB));
app.use('/db2', require('express-pouchdb')(PouchDB));
app.listen(3000);

Node immediately encounters UnhandledPromiseRejectionWarning: [object Object]. I can curl localhost:3000/db1 successfully but curl localhost:3000/db2 just hangs.

I try the following to create separate PouchDB instances:

// same setup as above
app.use(
    '/db3', require('express-pouchdb')(new PouchDB('db3', {prefix: 'db3/'})));
app.use(
    '/db4', require('express-pouchdb')(new PouchDB('db4', {prefix: 'db4/'})));
app.listen(3000);

Node will happily start, but when I curl localhost:3000/db3, Node throws: Error: express-pouchdb needs a PouchDB object to route a request!. I thought I gave it a PouchDB object though?

How do people run multiple PouchDBs in the same Node app with express-pouchdb?

(My end-goal is to have a separate PouchDB for each Passport.js-authenticated user. I don't want to use Pouch/Couch auth since there appear to be security issues in PouchDB-Server. And I want them to live in separate directories on the disk for isolation.)


Solution

  • It's helpful to think of the express app as being an actual CouchDB instance. From that perspective, consider how one creates a new database with CouchDB1:

    curl -X PUT http://127.0.0.1:5984/{db_name}

    From this perspective there is no need to create distinct PouchDB's for every database instance, rather create the databases as one would for CouchDB.

    This code simply spins up a server, placing all database files in a sub-directory2

    const express = require("express"),
      app = express(),
      PouchDB = require("pouchdb");
    // In the current directory, place all database files into a directory named 'database'
    const configPouchDB = PouchDB.defaults({ prefix: "./database/" });
    app.use("/", require("express-pouchdb")(configPouchDB));
    app.listen(3000);
    

    From the shell, fire up the server

    $ node app.js

    And from another shell, hit the default endpoint and we see the response is just CouchDB-like

    $ curl localhost:3000
    {"express-pouchdb":"Welcome!","version":"4.2.0","pouchdb-adapters":["leveldb"],"vendor":{"name":"PouchDB authors","version":"4.2.0"},"uuid":"00739d7f-3b78-4a73-b69c-0af98bd819e7"}

    Now that the server is running create databases as one may with CouchDB

    curl -X PUT http://localhost:3000/db1
    {"ok":true}
    curl -X PUT http://localhost:3000/db2 {"ok":true}

    Now if it is absolutely required to have specific pouchDB instances in the server code you could do the following (for this example code, delete the database directory first to demonstrate creation)

    const express = require("express"),
      app = express(),
      PouchDB = require("pouchdb");
    // In the current directory, place all database files into a directory named 'database'
    const configPouchDB = PouchDB.defaults({ prefix: "./database/" });
    app.use("/", require("express-pouchdb")(configPouchDB));
    app.listen(3000);
    //
    // create databases now 
    //
    const dbs = {
      db1: new PouchDB("db1"),
      db2: new PouchDB("db2"),
    };
    

    After the server fires up, curl will show the databases are created on startup.

    $ curl localhost:3000/db1
    {"doc_count":0,"update_seq":0,"backend_adapter":"LevelDOWN","db_name":"db1","auto_compaction":false,"adapter":"leveldb","disk_size":198,"instance_start_time":"1601040439637"}  
    
    $ curl localhost:3000/db2
    {"doc_count":0,"update_seq":0,"backend_adapter":"LevelDOWN","db_name":"db2","auto_compaction":false,"adapter":"leveldb","disk_size":197,"instance_start_time":"1601040439637"}

    Update I understand your use case better now after reading your comment. Consider this

    const express = require("express"),
      app = express(),
      PouchDB = require("pouchdb");
    // In the current directory, place all database files into a directory named 'database'
    const configPouchDB = PouchDB.defaults({ prefix: "./database/" });
    const db = require("express-pouchdb")(configPouchDB);
    
    app.use("/", (req, res) => {
      // this simply delegates the request.
      // here you can add conditional logic.
      db(req, res);
    });
    
    app.listen(3000);
    

    I recommend reading up on Express Middleware3 and Express Router4, the latter of which may provide efficient solutions.

    1. Create a CouchDB database
    2. Express-PouchDB defaults
    3. Express Middleware
    4. Express Router