Skip to content

srmurali002/node-red-contrib-db-storage

Repository files navigation

Node-RED Storage Plugin

A flexible storage plugin for Node-RED that supports multiple database backends including MongoDB, PostgreSQL, MySQL/MariaDB, and SQLite.

Features

  • Multi-database support: MongoDB, PostgreSQL, MySQL/MariaDB, SQLite
  • Store all Node-RED data in your preferred database
  • Separate collections/tables for each entity type
  • Configurable collection/table names
  • Support for Node-RED library entries
  • Backward compatible with existing MongoDB configurations
  • Extensible adapter registry - easily add custom database adapters
  • Standardized configuration interface across all adapters
  • Input validation and SQL injection protection

Installation

npm install node-red-contrib-db-storage

Database-specific dependencies

MongoDB (included by default):

# MongoDB driver is included

PostgreSQL:

npm install pg

MySQL/MariaDB:

npm install mysql2

SQLite:

npm install better-sqlite3

Requirements

  • Node.js >= 10.x
  • Node-RED (embedded mode)
  • One of the following databases:
    • MongoDB >= 3.4
    • PostgreSQL >= 9.6
    • MySQL >= 5.7 or MariaDB >= 10.2
    • SQLite 3

Quick Start

MongoDB Configuration

const settings = {
    storageModule: require('node-red-contrib-db-storage'),
    storageModuleOptions: {
        type: 'mongodb',
        url: 'mongodb://localhost:27017',
        database: 'nodered'
    }
};

PostgreSQL Configuration

const settings = {
    storageModule: require('node-red-contrib-db-storage'),
    storageModuleOptions: {
        type: 'postgres',
        url: 'postgresql://user:password@localhost:5432/nodered'
    }
};

MySQL/MariaDB Configuration

const settings = {
    storageModule: require('node-red-contrib-db-storage'),
    storageModuleOptions: {
        type: 'mysql',  // or 'mariadb'
        url: 'mysql://user:password@localhost:3306/nodered'
    }
};

SQLite Configuration

const settings = {
    storageModule: require('node-red-contrib-db-storage'),
    storageModuleOptions: {
        type: 'sqlite',
        url: '/path/to/nodered.db'
        // or use ':memory:' for in-memory database
    }
};

Usage

This plugin requires running Node-RED in embedded mode. See the Node-RED embedding guide for details.

Complete Example

const http = require('http');
const express = require('express');
const RED = require('node-red');

const app = express();
const server = http.createServer(app);

const settings = {
    httpAdminRoot: '/red',
    httpNodeRoot: '/api',
    userDir: './user',

    // Storage Plugin Configuration
    storageModule: require('node-red-contrib-db-storage'),
    storageModuleOptions: {
        type: 'mongodb',  // or 'postgres', 'mysql', 'sqlite'
        url: 'mongodb://localhost:27017',
        database: 'nodered',

        // Optional: custom collection/table names
        collectionNames: {
            flows: 'my-flows',
            credentials: 'my-credentials',
            settings: 'my-settings',
            sessions: 'my-sessions'
        }
    }
};

RED.init(server, settings);

app.use(settings.httpAdminRoot, RED.httpAdmin);
app.use(settings.httpNodeRoot, RED.httpNode);

server.listen(8000, () => {
    console.log('Node-RED server running on port 8000');
});

RED.start();

Configuration Options

Option Type Required Description
type string Yes* Database type: 'mongodb', 'postgres', 'mysql', 'sqlite'
url string Yes Database connection URL or file path
database string No** Database name
collectionNames object No Custom collection/table names

*For backward compatibility, mongoUrl or postgresUrl can be used instead of type + url

**Database name is automatically extracted from the URL for PostgreSQL, MySQL, and SQLite. Required for MongoDB if not in URL.

Legacy Configuration (Backward Compatible)

// Old MongoDB configuration still works
storageModuleOptions: {
    mongoUrl: 'mongodb://localhost:27017',
    database: 'nodered'
}

Environment Variables

const settings = {
    storageModule: require('node-red-contrib-db-storage'),
    storageModuleOptions: {
        type: process.env.DB_TYPE || 'mongodb',
        url: process.env.DATABASE_URL || 'mongodb://localhost:27017',
        database: process.env.DB_NAME || 'nodered'
    }
};

Default Collection/Table Names

Entity Default Name
Flows nodered-flows
Credentials nodered-credentials
Settings nodered-settings
Sessions nodered-sessions

API

The plugin implements the Node-RED storage module interface:

  • init(settings) - Initialize the storage module
  • getFlows() / saveFlows(flows) - Manage flows
  • getCredentials() / saveCredentials(credentials) - Manage credentials
  • getSettings() / saveSettings(settings) - Manage settings
  • getSessions() / saveSessions(sessions) - Manage sessions
  • getLibraryEntry(type, path) / saveLibraryEntry(type, path, meta, body) - Manage library entries
  • close() - Close database connection

Creating Custom Adapters

You can create your own database adapter by extending the DatabaseAdapter class and registering it with the factory:

const { DatabaseAdapter, AdapterFactory } = require('node-red-contrib-db-storage/adapters');

class MyCustomAdapter extends DatabaseAdapter {
    constructor(config) {
        super(config);
        // Initialize your adapter
        // this.url and this.databaseName are set by parent class
    }

    async connect() {
        // Connect to your database
    }

    async close() {
        // Close connection
    }

    async findAll(collectionName) {
        // Validate input (inherited from parent)
        this.validateCollectionName(collectionName);
        // Return all documents as array
    }

    async saveAll(collectionName, objects) {
        this.validateCollectionName(collectionName);
        this.validateObjectArray(objects);
        // Save all objects (replace existing)
    }

    async findOneByPath(collectionName, path) {
        this.validateCollectionName(collectionName);
        this.validatePath(path);
        // Find by path, return body or {}
    }

    async saveOrUpdateByPath(collectionName, path, meta, body) {
        this.validateCollectionName(collectionName);
        this.validatePath(path);
        // Upsert by path
    }
}

// Register the adapter with the factory
AdapterFactory.register(['mycustom', 'custom'], MyCustomAdapter);

// Now you can use it in configuration:
// { type: 'mycustom', url: '...', database: '...' }

Using the Adapter Registry

The AdapterFactory uses a registry pattern for extensibility:

const { AdapterFactory } = require('node-red-contrib-db-storage/adapters');

// Register a new adapter type
AdapterFactory.register('redis', RedisAdapter);

// Register with multiple aliases
AdapterFactory.register(['cockroachdb', 'crdb'], CockroachAdapter);

// Check if a type is registered
AdapterFactory.isRegistered('redis'); // true

// Get all supported types
AdapterFactory.getSupportedTypes(); // ['mongodb', 'postgres', 'mysql', 'sqlite', 'redis', ...]

// Unregister an adapter
AdapterFactory.unregister('redis');

Development

Setup

git clone https://github.com/srmurali002/node-red-contrib-db-storage.git
cd node-red-storage-plugin
npm install

Running Tests

Unit Tests (with mocks, no database required):

npm test
# or
npm run test:unit

Integration Tests (require running databases):

# Start test databases
npm run docker:up

# Run all integration tests
npm run test:integration

# Run MongoDB integration tests only
npm run test:integration:mongo

# Run PostgreSQL integration tests only
npm run test:integration:postgres

# Run all tests (unit + integration)
npm run test:all

# Stop test databases
npm run docker:down

Environment Variables for Integration Tests:

MONGO_URL=mongodb://localhost:27017
MONGO_DATABASE=nodered_test
POSTGRES_URL=postgresql://nodered:nodered@localhost:5432/nodered_test
TEST_DATABASES=mongodb,postgres  # or just one
SKIP_INTEGRATION=true  # skip integration tests

Project Structure

node-red-contrib-db-storage/
├── index.js                    # Main module
├── constants.js                # Default configuration
├── adapters/
│   ├── index.js               # Adapter exports
│   ├── DatabaseAdapter.js     # Base adapter class
│   ├── AdapterFactory.js      # Adapter factory with registry
│   ├── MongoAdapter.js        # MongoDB implementation
│   ├── PostgresAdapter.js     # PostgreSQL implementation
│   ├── MySQLAdapter.js        # MySQL/MariaDB implementation
│   └── SQLiteAdapter.js       # SQLite implementation
├── utils/
│   ├── index.js               # Utility exports
│   └── UrlParser.js           # URL parsing utilities
├── tests/
│   └── UrlParser.test.js      # URL parser tests
├── examples/
│   └── node-red-app.js        # Example application
└── package.json

Troubleshooting

Common Issues

"storageModuleOptions is required"

Cause: The settings object passed to Node-RED is missing the storageModuleOptions property.

Solution: Ensure your settings include the required options:

const settings = {
    storageModule: require('node-red-contrib-db-storage'),
    storageModuleOptions: {
        type: 'mongodb',
        url: 'mongodb://localhost:27017',
        database: 'nodered'
    }
};

"Database URL is required"

Cause: No database URL was provided in the configuration.

Solution: Provide either:

  • url with type (new format)
  • mongoUrl (legacy MongoDB format)
  • postgresUrl (legacy PostgreSQL format)

"Database name is required"

Cause: The database name could not be determined from the URL or configuration.

Solution: Either include the database name in the URL or add the database property:

storageModuleOptions: {
    type: 'mongodb',
    url: 'mongodb://localhost:27017/nodered',  // Database in URL
    // or
    database: 'nodered'  // Explicit database name
}

"PostgreSQL adapter requires the 'pg' package"

Cause: The pg package is not installed but you're trying to use PostgreSQL.

Solution: Install the PostgreSQL driver:

npm install pg

"MySQL adapter requires the 'mysql2' package"

Cause: The mysql2 package is not installed but you're trying to use MySQL/MariaDB.

Solution: Install the MySQL driver:

npm install mysql2

"SQLite adapter requires the 'better-sqlite3' package"

Cause: The better-sqlite3 package is not installed but you're trying to use SQLite.

Solution: Install the SQLite driver:

npm install better-sqlite3

Connection Timeouts

Cause: Database server is not running or not accessible.

Solutions:

  1. Verify the database server is running
  2. Check the connection URL is correct
  3. Ensure network/firewall allows the connection
  4. For Docker, ensure the container is healthy:
    docker ps
    docker logs <container-name>

Data Not Persisting

Cause: Multiple Node-RED instances using the same database, or data being overwritten.

Solutions:

  1. Use unique collection names for each Node-RED instance
  2. Check that saveFlows() is being called on deploy
  3. Verify database connection is still active

Debug Mode

Enable debug logging by setting the DEBUG environment variable:

DEBUG=* node your-app.js

Database-Specific Issues

MongoDB: "MongoNetworkError"

  • Check MongoDB is running: mongosh --eval "db.runCommand('ping')"
  • Verify connection string format: mongodb://[user:pass@]host[:port]

PostgreSQL: "ECONNREFUSED"

  • Check PostgreSQL is running: pg_isready
  • Verify connection string format: postgresql://user:pass@host:port/database
  • Ensure the database exists: psql -l

MySQL: "ECONNREFUSED" or "Access denied"

  • Check MySQL is running: mysqladmin ping
  • Verify connection string format: mysql://user:pass@host:port/database
  • Ensure user has necessary permissions: GRANT ALL PRIVILEGES ON database.* TO 'user'@'host'

SQLite: "SQLITE_CANTOPEN"

  • Ensure the directory for the database file exists
  • Check file permissions for the target path
  • For in-memory databases, use :memory: as the URL

Getting Help

If you're still experiencing issues:

  1. Check existing issues
  2. Create a new issue with:
    • Node.js version
    • Node-RED version
    • Database type and version
    • Full error message and stack trace
    • Configuration (without sensitive data)

Changelog

v0.3.0 (2025)

  • Added MySQL/MariaDB adapter
  • Added SQLite adapter
  • New: Adapter registry pattern for extensibility (Open/Closed Principle)
  • New: URL parsing utility for automatic database name extraction
  • New: Input validation to prevent SQL injection
  • Refactored to encapsulate module state
  • Standardized configuration interface across all adapters
  • Comprehensive test coverage (136 tests)

v0.2.0 (2025)

  • Breaking: Restructured to support multiple databases
  • Added PostgreSQL adapter
  • Added database adapter abstraction layer
  • Added AdapterFactory for creating adapters
  • Backward compatible with existing MongoDB configurations
  • Improved error handling and validation
  • Comprehensive test suite

v0.1.3 (2025)

  • Fixed critical bugs in MongoDB operations
  • Added unit tests

v0.1.2 (2019)

  • Added configurable collection names

Roadmap

  • Integration tests
  • MySQL/MariaDB adapter
  • SQLite adapter
  • Adapter registry pattern
  • Input validation and security
  • Redis adapter
  • Connection pooling configuration
  • Retry logic for connection failures
  • TypeScript definitions
  • Migration utilities between databases
  • Per-data-type adapter configuration (e.g., Redis for sessions, PostgreSQL for flows)

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Adding a New Database Adapter

  1. Create a new adapter file in adapters/ extending DatabaseAdapter
  2. Register it with AdapterFactory.register() in AdapterFactory.js
  3. Export it from adapters/index.js
  4. Add unit tests in adapters/YourAdapter.test.js
  5. Add integration tests in adapters/YourAdapter.integration.test.js
  6. Update documentation in README.md

License

MIT License - see the LICENSE file for details.

Credits

Multi-database support and continued development by Muralidhar Reddy Challa.

Support

If you encounter any issues or have questions, please open an issue.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •