s3db.js: S3 Document Database ORM

21.6.2 · active · verified Wed Apr 22

s3db.js transforms AWS S3 into a powerful, cost-effective document database by leveraging S3's metadata capabilities to store document data up to 2KB per object, providing a serverless ORM-like interface. Currently at version 21.6.2, the library maintains an active release cadence with frequent patch and minor updates, indicating ongoing development and feature expansion. It differentiates itself by offering automatic encryption, schema validation, a streaming API for efficient data handling, and an extensive plugin architecture that supports multi-backend operations, including `RedDBClient` and integration with various other AWS services and external databases. Designed for serverless applications, cost-conscious projects, and rapid prototyping, it aims to reduce database management overhead. While its core leverages S3 for storage, its `DatabaseManager` allows integration with alternative storage backends and services, making it a flexible solution for diverse cloud data needs.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to initialize `s3db.js` with an S3 backend, define a `Model` with a schema, and perform basic CRUD operations (create, find, update, delete) on document data.

import { DatabaseManager, Model, Field } from 's3db.js';
import { S3Client } from '@aws-sdk/client-s3';

// Initialize AWS S3 Client with credentials from environment variables
const s3Client = new S3Client({
  region: process.env.AWS_REGION ?? 'us-east-1',
  credentials: {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID ?? '', 
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY ?? '',
  },
});

// Configure DatabaseManager for the S3 backend
const dbManager = new DatabaseManager({
  backends: {
    s3: {
      type: 's3',
      client: s3Client,
      bucketName: process.env.S3_BUCKET_NAME ?? 'my-s3db-test-bucket',
      prefix: 'my-app-data/', // Optional: prefix for keys within the bucket
    },
  },
  defaultBackend: 's3',
});

// Define a User Model with a schema
class User extends Model {
  static schema = {
    id: Field.id(), // Primary key
    name: Field.string({ required: true, maxLength: 100 }),
    email: Field.string({ required: true, unique: true, validator: (v: string) => v.includes('@') }),
    age: Field.number({ min: 18, max: 120, optional: true }),
    isActive: Field.boolean({ default: true }),
    createdAt: Field.timestamp({ auto: true }),
  };

  constructor(data?: any, options?: any) {
    super(data, { ...options, dbManager, backend: 's3' });
  }
}

async function runS3DBExample() {
  // Ensure S3 bucket exists and credentials are valid.
  await dbManager.connect();
  console.log('Connected to S3DB backend.');

  try {
    // 1. Create a new user
    const newUser = new User({
      name: 'Alice Wonderland',
      email: 'alice@example.com',
      age: 30,
    });
    const createdUser = await newUser.insert();
    console.log('Created User:', createdUser.toObject());

    // 2. Find a user by ID
    const foundUser = await User.findById(createdUser.id); // Static method for finding by ID
    if (foundUser) {
      console.log('Found User by ID:', foundUser.toObject());

      // 3. Update the user
      foundUser.age = 31;
      foundUser.isActive = false;
      const updatedUser = await foundUser.update();
      console.log('Updated User:', updatedUser.toObject());
    }

    // 4. List all users (note: for S3 metadata, complex queries might involve scanning)
    const allUsers = await User.findMany({}); // Fetches all documents under the model's prefix
    console.log(`Total users found: ${allUsers.length}`);
    if (allUsers.length > 0) {
      console.log('First user from findMany:', allUsers[0].toObject());
    }

    // 5. Delete the user
    if (foundUser) {
      await foundUser.delete();
      console.log(`Deleted User with ID: ${foundUser.id}`);
    }

  } catch (error) {
    console.error('Error during S3DB operations:', error);
  } finally {
    // In S3's stateless nature, explicit disconnects are often not needed, 
    // but a manager might offer a cleanup method.
  }
}

runS3DBExample();

view raw JSON →