CamaDB: TypeScript Embedded NoSQL Database
CamaDB is an embedded NoSQL database written in pure TypeScript, supporting Node.js, Electron, and browser environments. Its current stable version is 2.0.0 (January 2023), and it is under active development. CamaDB provides a MongoDB-style API for querying (SiftJS), updating (Obop), and aggregation (Mingo, with some limitations), offering full TypeScript support. It differentiates itself by providing frictionless integration across runtimes, handling native JavaScript data types, and aiming for fast performance on datasets up to 1 million rows, bypassing common issues with native database bindings in environments like Electron.
Common errors
-
ReferenceError: Reflect is not defined
cause The `reflect-metadata` polyfill was not imported or configured correctly, which CamaDB relies on for TypeScript type reflection.fixAdd `import "reflect-metadata";` at the top of your main application entry file. Also, ensure `emitDecoratorMetadata` and `experimentalDecorators` are `true` in your `tsconfig.json`. -
Error: Persistence adapter 'fs' requires a Node.js environment.
cause Attempting to use a persistence adapter (e.g., 'fs') in an unsupported JavaScript runtime (e.g., browser), or conversely, trying to use a browser-specific adapter in Node.js.fixConfigure the `persistenceAdapter` option during `Cama` initialization to match your target environment: use `'fs'` for Node.js/Electron, and `'indexeddb'` or `'localstorage'` for browser-based applications. -
TypeError: Cannot read properties of undefined (reading 'toISOString')
cause Inserting or retrieving a `Date` object into a collection column that was not explicitly defined with `type: 'date'` in the `initCollection` options, leading to incorrect serialization/deserialization.fixWhen initializing a collection via `database.initCollection`, ensure that any columns intended to store `Date` objects have `type: 'date'` specified in their column definition, e.g., `{ type: 'date', title: 'myDateColumn' }`. -
Error: Collection 'myCollectionName' already exists.
cause Attempting to call `database.initCollection()` for a collection that has already been initialized on the current database instance, which is not permitted.fixEnsure `database.initCollection()` is called only once per collection name per database instance. Store the returned `Collection` instance and reuse it throughout your application.
Warnings
- breaking Version 2.0.0 introduced a breaking change by centralizing the internal queuing system. This may affect applications that interacted directly with previous internal queue mechanisms or custom persistence adapters.
- gotcha Indexes are not yet implemented, which may impact query performance on very large datasets, especially without highly selective filters. The library states it is fast even without them, but complex queries might suffer.
- gotcha Rich text search functionality is currently missing. For full-text search capabilities, an external library or custom implementation is required.
- gotcha The Mingo-powered aggregation engine in CamaDB does not support all MongoDB aggregation commands, specifically 'lookup' commands are not available.
- gotcha CamaDB uses `reflect-metadata` for type reflection. If not configured correctly (e.g., missing import, `tsconfig.json` settings), this can lead to runtime errors, particularly with features relying on decorator metadata.
Install
-
npm install camadb -
yarn add camadb -
pnpm add camadb
Imports
- Cama
const { Cama } = require('camadb');import { Cama } from 'camadb'; - CamaConfig
import { CamaConfig } from 'camadb';import type { CamaConfig } from 'camadb'; - Collection
import { Collection } from 'camadb';const collection = await database.initCollection(...);
Quickstart
import { Cama } from 'camadb';
// Ensure reflect-metadata is imported if decorators are used, often at the top level
// import 'reflect-metadata';
interface User {
_id: string;
name: string;
email: string;
registrationDate: Date;
preferences: {
theme: string;
notifications: boolean;
};
}
async function setupCamaDB() {
// Initialize the database instance with filesystem persistence
const database = new Cama({
path: './.cama-data',
persistenceAdapter: 'fs', // Use 'indexeddb' or 'localstorage' for browser environments
logLevel: 'info' // Can be 'debug' for more verbose logging
});
// Initialize a collection named 'users' with a specific date column for proper type handling
const usersCollection = await database.initCollection<User>('users', {
columns: [{
type: 'date',
title: 'registrationDate' // Essential for CamaDB to correctly store and retrieve Date objects
}],
indexes: [], // Indexes are not yet implemented but are part of the configuration API
});
// Insert a new user document into the collection
const newUser: User = {
_id: 'user_001',
name: 'Alice Wonderland',
email: 'alice@example.com',
registrationDate: new Date(),
preferences: {
theme: 'dark',
notifications: true
}
};
await usersCollection.insertOne(newUser);
console.log('User inserted successfully:', newUser._id);
// Example of finding a user by _id
const foundUser = await usersCollection.findMany({ _id: 'user_001' });
console.log('Found user:', foundUser);
// Example of updating a user's preferences
await usersCollection.updateMany({
_id: 'user_001'
}, {
$set: {
'preferences.theme': 'light'
}
});
console.log('User preferences updated.');
}
setupCamaDB().catch(console.error);