LiekoDB Documentation

A lightweight, MongoDB-like JSON database for Node.js with local and HTTP modes

Introduction

LiekoDB is a fast, lightweight JSON database inspired by MongoDB. It supports two operation modes:

  • Local Mode
    Store data in JSON files on your filesystem (Node.js only)
  • HTTP Mode
    Connect to a remote LiekoDB server using HTTP client
Note: Local mode is only available in Node.js. Browser environments require HTTP mode with a token.

Installation

NPM

npm install liekodb

Yarn

yarn add liekodb

Basic Usage

const LiekoDB = require('liekodb');

const db = new LiekoDB({
  storagePath: './storage',
  debug: true
});

const users = db.collection('users');

Configuration

Local Mode (Node.js)

const db = new LiekoDB({
  storagePath: './storage',      // Storage directory
  autoSaveInterval: 5000,         // Auto-save every 5s
  debug: true                     // Enable detailed logs
});

HTTP Mode (Client)

const db = new LiekoDB({
  databaseUrl: 'http://127.0.0.1:8050',
  token: 'your-auth-token',       // Required for HTTP mode
  poolSize: 10,                   // Connection pool size
  timeout: 15000,                 // Request timeout (ms)
  debug: true
});

Configuration Options

Option Type Default Description
storagePath string './storage' Directory for JSON files (Local mode)
autoSaveInterval number 5000 Auto-save interval in milliseconds
debug boolean false Enable detailed logging
databaseUrl string - Remote database URL (HTTP mode)
token string - Authentication token (HTTP mode)
poolSize number 10 HTTP connection pool size
timeout number 15000 Request timeout in milliseconds

Insert Documents

Add new documents to a collection. Supports single or bulk insertion with automatic ID generation.

Insert Single Document

const { error, data } = await users.insert({
  username: 'alice',
  email: 'alice@example.com',
  age: 28
});

console.log(data);
// {
//   insertedCount: 1,
//   insertedIds: ['abc123def456'],
//   totalDocuments: 1
// }

Insert Multiple Documents

const { error, data } = await users.insert([
  { username: 'bob', email: 'bob@example.com', age: 32 },
  { username: 'charlie', email: 'charlie@example.com', age: 25 }
]);

console.log(data);
// {
//   insertedCount: 2,
//   firstId: '1a2b3c4d5e6f7890',
//   lastId: '1a2b3c4d5e6f7891',
//   totalDocuments: 3
// }

Upsert (Insert or Update)

// If document with this ID exists, it will be updated
// Otherwise, it will be inserted
const { error, data } = await users.insert({
  id: 'user_123',
  username: 'alice',
  email: 'alice_updated@example.com'
});

console.log(data);
// {
//   insertedCount: 0,
//   updatedCount: 1,
//   totalDocuments: 3
// }
Documents automatically receive id, createdAt, and updatedAt fields.

Find Documents

Query documents with filters, sorting, and pagination.

Find All Documents

const { error, data } = await users.find();

console.log(data.foundDocuments);
// [ { id: '...', username: 'alice', ... }, ... ]

Find with Filters

const { error, data } = await users.find(
  { age: { $gte: 25 } },
  {
    sort: { age: -1 },
    limit: 10,
    fields: { username: 1, email: 1 }
  }
);

console.log(data);
// {
//   foundCount: 5,
//   foundDocuments: [...],
//   totalDocuments: 20
// }

Find One Document

const { error, data } = await users.findOne(
  { email: 'alice@example.com' }
);

console.log(data); // Document or null

Find by ID

const { error, data } = await users.findById('user_123');

console.log(data); // Document or null

Query Options

Option Type Description
sort object Sort results (1 ascending, -1 descending)
limit number Maximum number of results
skip number Number of documents to skip
page number Page number (alternative to skip)
fields object Field projection (1 include, -1 exclude)

Update Documents

Modify existing documents using update operators.

Update by ID

const { error, data } = await users.updateById(
  'user_123',
  { $inc: { loginCount: 1 } },
  { returnType: 'document' }
);

console.log(data.document); // Updated document

Update Multiple Documents

const { error, data } = await users.update(
  { age: { $lt: 30 } },
  { $set: { status: 'young' } },
  { returnType: 'count' }
);

console.log(data);
// {
//   updatedCount: 15,
//   totalDocuments: 100
// }

Update Operators

// $set - Set a value
await users.update({}, { $set: { verified: true } });

// $inc - Increment
await users.update({}, { $inc: { visits: 1 } });

// $push - Add to array
await users.update({}, { $push: { tags: 'premium' } });

// $addToSet - Add without duplicates
await users.update({}, { $addToSet: { roles: 'admin' } });

// $pull - Remove from array
await users.update({}, { $pull: { tags: 'banned' } });

// $unset - Remove field
await users.update({}, { $unset: { tempField: 1 } });

Update Nested Fields

await domains.update(
  { name: 'example.com' },
  { $set: { 'serverMOTD.raw': 'New message' } }
);

Return Types

Type Description
count Returns only the count of updated documents
ids Returns IDs of updated documents
documents Returns full updated documents

Delete Documents

Remove documents from collections.

Delete by ID

const { error, data } = await users.deleteById('user_123');

console.log(data);
// {
//   deletedCount: 1,
//   deletedId: 'user_123'
// }

Delete Multiple by IDs

const { error, data } = await users.delete({ 
  id: { $in: ['user_123', 'user_456', 'user_789'] } 
});

console.log(data);
// {
//   collectionName: 'users',
//   deletedCount: 3
// }

Delete with Filters

const { error, data } = await users.delete({ 
  age: { $lt: 18 } 
});

console.log(data);
// {
//   collectionName: 'users',
//   deletedCount: 5
// }

Drop Collection

const { error, data } = await users.drop();

console.log(data);
// {
//   collectionName: 'users',
//   dropped: true
// }
Warning: The delete() method requires filters to prevent accidental deletion of all documents. Use drop() to delete the entire collection.

Count Documents

Get the number of documents matching a filter.

Count All Documents

const { error, data } = await users.count();

console.log(data); // 150

Count with Filters

const { error, data } = await users.count({ 
  age: { $gte: 25 } 
});

console.log(data); // 42

Filters & Operators

LiekoDB supports MongoDB-like query operators for filtering documents.

Complete Operators Reference

Operator Category Description Example
$eq Comparison Matches values that are equal to a specified value { age: { $eq: 25 } }
$ne Comparison Matches values that are not equal to a specified value { status: { $ne: 'banned' } }
$gt Comparison Matches values that are greater than a specified value { age: { $gt: 18 } }
$gte Comparison Matches values that are greater than or equal to a specified value { age: { $gte: 18 } }
$lt Comparison Matches values that are less than a specified value { age: { $lt: 65 } }
$lte Comparison Matches values that are less than or equal to a specified value { age: { $lte: 65 } }
$in Comparison Matches any of the values specified in an array { status: { $in: ['active', 'pending'] } }
$nin Comparison Matches none of the values specified in an array { role: { $nin: ['admin', 'mod'] } }
$and Logical Joins query clauses with a logical AND { $and: [{ age: { $gte: 18 } }, { status: 'active' }] }
$or Logical Joins query clauses with a logical OR { $or: [{ role: 'admin' }, { role: 'mod' }] }
$not Logical Inverts the effect of a query expression { age: { $not: { $lt: 18 } } }
$nor Logical Joins query clauses with a logical NOR { $nor: [{ banned: true }, { deleted: true }] }
$exists Element Matches documents that have the specified field { email: { $exists: true } }
$regex Evaluation Matches values that match a specified regular expression { email: { $regex: /@gmail\.com$/ } }
$mod Evaluation Performs a modulo operation on the value of a field { age: { $mod: [2, 0] } }

Comparison Operators

// $eq - Equal
await users.find({ age: 25 });
await users.find({ age: { $eq: 25 } });

// $ne - Not equal
await users.find({ status: { $ne: 'banned' } });

// $gt, $gte, $lt, $lte - Greater/Less than
await users.find({ age: { $gte: 18, $lt: 65 } });

// $in - In array
await users.find({ 
  status: { $in: ['active', 'pending'] } 
});

// $nin - Not in array
await users.find({ 
  role: { $nin: ['admin', 'moderator'] } 
});

Logical Operators

By default, multiple filter conditions separated by commas act as a logical AND. You only need $and for complex nested queries.

// Implicit $and - Multiple conditions (recommended)
await users.find({
  age: { $gte: 18 },
  status: 'active'
});

// Explicit $and - Same result, more verbose
await users.find({
  $and: [
    { age: { $gte: 18 } },
    { status: 'active' }
  ]
});

// $or - At least one condition must match
await users.find({
  $or: [
    { role: 'admin' },
    { role: 'moderator' }
  ]
});

// $not - Negation
await users.find({ 
  age: { $not: { $lt: 18 } } 
});

// $nor - None of the conditions match
await users.find({
  $nor: [
    { banned: true },
    { deleted: true }
  ]
});

// Combining implicit AND with $or
await users.find({
  status: 'active',  // Implicit AND
  $or: [
    { role: 'admin' },
    { role: 'moderator' }
  ]
});

Special Operators

// $exists - Field exists
await users.find({ 
  email: { $exists: true } 
});

// $regex - Regular expression
await users.find({ 
  email: { $regex: /@gmail\.com$/ } 
});

// $mod - Modulo operation
await users.find({ 
  age: { $mod: [2, 0] }  // Even ages
});

Array Queries

// Match value in array
await users.find({ tags: 'premium' });

// Match any value
await users.find({ 
  tags: { $in: ['vip', 'premium'] } 
});

Nested Fields (Dot Notation)

await domains.find({ 
  'serverMOTD.raw': 'A Minecraft Server' 
});

await users.find({ 
  'address.city': 'Paris' 
});

Pagination

LiekoDB provides flexible pagination with automatic metadata.

Basic Pagination

const { error, data } = await users.find({}, {
  limit: 20,
  page: 2
});

console.log(data.pagination);
// {
//   page: 2,
//   limit: 20,
//   total: 150,
//   totalPages: 8,
//   hasNext: true,
//   hasPrev: true,
//   nextPage: 3,
//   prevPage: 1,
//   startIndex: 21,
//   endIndex: 40
// }

Using Skip

const { error, data } = await users.find({}, {
  limit: 20,
  skip: 40  // Skip first 40 documents
});

Sorting with Pagination

const { error, data } = await users.find(
  { status: 'active' },
  {
    sort: { createdAt: -1 },
    limit: 20,
    page: 1
  }
);

Field Projection

Select or exclude specific fields from query results.

Include Fields

const { error, data } = await users.find({}, {
  fields: { username: 1, email: 1 }
});

// Only returns: { username: '...', email: '...' }

Exclude Fields

const { error, data } = await users.find({}, {
  fields: { password: -1, apiKey: -1 }
});

// Returns all fields except password and apiKey
Note: Cannot mix inclusion and exclusion in the same projection.

Database Management

Manage collections and database status.

List Collections

const collections = await db.listCollections();

console.log(collections);
// [
//   {
//     name: 'users',
//     totalDocuments: 150,
//     sizeBytes: 45120,
//     sizeFormatted: '44.06 KB'
//   },
//   {
//     name: 'domains',
//     totalDocuments: 42,
//     sizeBytes: 12340,
//     sizeFormatted: '12.05 KB'
//   }
// ]

Database Status

const status = await db.status();

console.log(status);
// {
//   storagePath: './storage',
//   collections: [...],
//   totalCollections: 5,
//   totalDocuments: 1250,
//   totalCollectionsSize: 2048576,
//   totalCollectionsSizeFormatted: '2.00 MB'
// }

Close Database

// Flush all pending writes and close connections
await db.close();

Error Handling

All operations return a standardized response format with error handling.

Response Format

const { error, data } = await users.findById('unknown_id');

if (error) {
  console.error('Error:', error.message);
  console.error('Code:', error.code);
  return;
}

console.log('Result:', data);

Error Object Structure

{
  error: {
    message: "Error description",
    code: 500
  }
}

Common Error Scenarios

Error Description
Collection name must be a non-empty string Invalid collection name provided
Filters must be a non-null plain object Invalid filter format
Invalid query operator Unknown or unsupported operator used
Document not found No document matches the query
Delete operation requires filters Must provide filters to prevent accidental deletion

Data Objects

Document Structure

All documents automatically include these fields:

  • id string
    Unique identifier (auto-generated if not provided)
  • createdAt string
    ISO 8601 timestamp of creation
  • updatedAt string
    ISO 8601 timestamp of last update

Example Document

{
  "id": "abc123def456",
  "username": "alice",
  "email": "alice@example.com",
  "age": 28,
  "createdAt": "2026-01-05T10:30:00.000Z",
  "updatedAt": "2026-01-05T10:30:00.000Z"
}

Best Practices

Follow these guidelines to use LiekoDB effectively and avoid common pitfalls.

Collection Design

// ✅ Good: Descriptive, singular names
const users = db.collection('users');
const orders = db.collection('orders');

// ❌ Avoid: Generic or unclear names
const data = db.collection('data');
const temp = db.collection('temp');
  • Use descriptive names
    Choose clear, meaningful collection names that describe the data they contain
  • Keep names consistent
    Use a consistent naming convention (camelCase or snake_case)
  • Avoid special characters
    Stick to alphanumeric characters, hyphens, and underscores

Query Optimization

// ✅ Good: Use field projection to reduce data transfer
const { data } = await users.find(
  { status: 'active' },
  { fields: { username: 1, email: 1 } }
);

// ✅ Good: Use pagination for large datasets
const { data } = await users.find(
  {},
  { limit: 50, page: 1 }
);

// ❌ Avoid: Fetching all data without limits
const { data } = await users.find({});
  • Always use pagination
    Limit results to avoid loading large datasets into memory
  • Project only needed fields
    Use field projection to reduce response size
  • Use specific filters
    Narrow queries with precise filters to improve performance

Error Handling

// ✅ Good: Always check for errors
const { error, data } = await users.findById('user_123');

if (error) {
  console.error('Query failed:', error.message);
  return;
}

console.log('User found:', data);

// ✅ Good: Use try-catch for operations
try {
  const result = await users.insert({ username: 'alice' });
  if (result.error) {
    console.error('Insert failed:', result.error);
  }
} catch (err) {
  console.error('Unexpected error:', err);
}
  • Always handle errors
    Check the error field in responses before accessing data
  • Use try-catch blocks
    Wrap operations in try-catch to handle unexpected errors
  • Log errors appropriately
    Log errors with context to facilitate debugging

Data Validation

// ✅ Good: Validate data before insertion
const validateUser = (user) => {
  if (!user.username || user.username.length < 3) {
    throw new Error('Username must be at least 3 characters');
  }
  if (!user.email || !user.email.includes('@')) {
    throw new Error('Invalid email address');
  }
  return true;
};

try {
  validateUser(userData);
  await users.insert(userData);
} catch (err) {
  console.error('Validation failed:', err.message);
}
  • Validate before operations
    Check data integrity before inserting or updating
  • Use consistent schemas
    Maintain consistent document structure within collections
  • Handle type conversions
    Ensure data types are correct before storing

Update Operations

// ✅ Good: Use update operators for atomic updates
await users.updateById('user_123', {
  $inc: { loginCount: 1 },
  $set: { lastLogin: new Date().toISOString() }
});

// ✅ Good: Update specific fields
await users.update(
  { status: 'pending' },
  { $set: { status: 'active' } }
);

// ❌ Avoid: Replacing entire documents unnecessarily
await users.updateById('user_123', {
  username: 'alice',
  email: 'alice@example.com',
  // ... all other fields
});
  • Use atomic operators
    Prefer $inc, $push, $set for safer, more efficient updates
  • Update only changed fields
    Avoid replacing entire documents when only few fields change
  • Check update results
    Verify updatedCount to ensure operations succeeded

Delete Operations

// ✅ Good: Always provide filters for delete()
await users.delete({ inactive: true, lastLogin: { $lt: '2025-01-01' } });

// ✅ Good: Use deleteById for single documents
await users.deleteById('user_123');

// ✅ Good: Use drop() to clear entire collection
await users.drop();

// ❌ Avoid: This will throw an error
await users.delete({});  // Error: filters required
Warning: Delete operations are permanent. Always double-check filters before deleting documents.

Performance Tips

  • Use bulk inserts
    Insert multiple documents at once instead of individual operations
  • Enable debug mode during development
    Set debug: true to monitor performance and identify bottlenecks
  • Adjust auto-save interval
    Balance between data safety and performance (default: 5000ms)
  • Close database on shutdown
    Always call db.close() to ensure all data is saved
  • Monitor collection sizes
    Use db.status() to track storage usage

HTTP Mode Best Practices

// ✅ Good: Configure connection pooling
const db = new LiekoDB({
  databaseUrl: 'http://127.0.0.1:8050',
  token: 'your-auth-token',
  poolSize: 10,        // Adjust based on concurrent requests
  timeout: 15000       // Set appropriate timeout
});

// ✅ Good: Reuse database instance
const dbInstance = new LiekoDB({ token: 'your-token' });
const users = dbInstance.collection('users');
const orders = dbInstance.collection('orders');
  • Secure your token
    Never expose authentication tokens in client-side code
  • Configure pool size
    Adjust poolSize based on expected concurrent requests
  • Set appropriate timeouts
    Balance between reliability and responsiveness
  • Reuse database instances
    Create one instance and reuse for all collections

Basic CRUD Operations

Simple example covering insert, find, update, and delete operations.

const LiekoDB = require('liekodb');

const db = new LiekoDB({
    storagePath: './storage',
    debug: true
});

const users = db.collection('users');

async function basicCRUD() {
    // Insert users
    console.log('=== Inserting users ===');
    await users.insert([
        { username: 'alice', email: 'alice@example.com', age: 28, role: 'admin' },
        { username: 'bob', email: 'bob@example.com', age: 32, role: 'user' },
        { username: 'charlie', email: 'charlie@example.com', age: 25, role: 'user' }
    ]);

    // Find all users
    console.log('\n=== Finding all users ===');
    const { data: allUsers } = await users.find();
    console.log(`Found ${allUsers.foundCount} users`);

    // Find specific user
    console.log('\n=== Finding user by email ===');
    const { data: alice } = await users.findOne({ email: 'alice@example.com' });
    console.log('User:', alice);

    // Update user
    console.log('\n=== Updating user ===');
    await users.update(
        { username: 'alice' },
        { $set: { age: 29 } }
    );

    // Delete user
    console.log('\n=== Deleting user ===');
    await users.delete({ username: 'charlie' });

    // Final count
    const count = await users.count();
    console.log(`\nFinal count: ${count.data} users`);

    await db.close();
}

basicCRUD().catch(console.error);

Pagination Example

Implement pagination with sorting and field projection.

const LiekoDB = require('liekodb');

const db = new LiekoDB({
    storagePath: './storage',
    debug: true
});

const products = db.collection('products');

async function paginationExample() {
    // Insert sample products
    console.log('=== Inserting products ===');
    const productList = [];
    for (let i = 1; i <= 50; i++) {
        productList.push({
            name: `Product ${i}`,
            price: Math.floor(Math.random() * 1000) + 10,
            category: ['Electronics', 'Clothing', 'Books', 'Home'][Math.floor(Math.random() * 4)],
            stock: Math.floor(Math.random() * 100)
        });
    }
    await products.insert(productList);

    // Paginated query
    console.log('\n=== Page 1 (10 items per page) ===');
    const { data: page1 } = await products.find(
        { price: { $gte: 100 } },
        {
            sort: { price: -1 },
            limit: 10,
            page: 1,
            fields: { name: 1, price: 1, category: 1 }
        }
    );

    console.log(`Found ${page1.foundCount} products on this page`);
    console.log(`Total matching: ${page1.pagination.total}`);
    console.log(`Page ${page1.pagination.page} of ${page1.pagination.totalPages}`);
    console.log(`Has next page: ${page1.pagination.hasNext}`);

    page1.foundDocuments.forEach((product, idx) => {
        console.log(`${idx + 1}. ${product.name} - $${product.price}`);
    });

    // Get next page
    if (page1.pagination.hasNext) {
        console.log('\n=== Page 2 ===');
        const { data: page2 } = await products.find(
            { price: { $gte: 100 } },
            {
                sort: { price: -1 },
                limit: 10,
                page: 2,
                fields: { name: 1, price: 1 }
            }
        );

        page2.foundDocuments.forEach((product, idx) => {
            console.log(`${idx + 1}. ${product.name} - $${product.price}`);
        });
    }

    await db.close();
}

paginationExample().catch(console.error);

Advanced Filtering

Complex queries with multiple operators and nested conditions.

const LiekoDB = require('liekodb');

const db = new LiekoDB({
    storagePath: './storage',
    debug: true
});

const orders = db.collection('orders');

async function advancedFiltering() {
    // Insert sample orders
    console.log('=== Inserting orders ===');
    await orders.insert([
        {
            orderId: 'ORD001',
            customer: { name: 'Alice', email: 'alice@example.com', vip: true },
            items: ['laptop', 'mouse', 'keyboard'],
            total: 1250.50,
            status: 'completed',
            shippedAt: '2025-01-05T10:00:00Z'
        },
        {
            orderId: 'ORD002',
            customer: { name: 'Bob', email: 'bob@example.com', vip: false },
            items: ['phone'],
            total: 899.99,
            status: 'pending',
            shippedAt: null
        },
        {
            orderId: 'ORD003',
            customer: { name: 'Charlie', email: 'charlie@gmail.com', vip: true },
            items: ['tablet', 'case'],
            total: 450.00,
            status: 'completed',
            shippedAt: '2025-01-07T14:30:00Z'
        },
        {
            orderId: 'ORD004',
            customer: { name: 'Diana', email: 'diana@example.com', vip: false },
            items: ['headphones'],
            total: 150.00,
            status: 'cancelled',
            shippedAt: null
        },
        {
            orderId: 'ORD005',
            customer: { name: 'Eve', email: 'eve@gmail.com', vip: true },
            items: ['monitor', 'cable', 'adapter'],
            total: 650.00,
            status: 'pending',
            shippedAt: null
        }
    ]);

    // Complex filter 1: VIP customers with completed orders over $500
    console.log('\n=== VIP customers with completed orders > $500 ===');
    const { data: vipOrders } = await orders.find({
        'customer.vip': true,
        status: 'completed',
        total: { $gt: 500 }
    });
    console.log(`Found ${vipOrders.foundCount} orders`);
    vipOrders.foundDocuments.forEach(order => {
        console.log(`- ${order.orderId}: ${order.customer.name} - $${order.total}`);
    });

    // Complex filter 2: Gmail users OR orders with multiple items
    console.log('\n=== Gmail users OR orders with 3+ items ===');
    const { data: complexOrders } = await orders.find({
        $or: [
            { 'customer.email': { $regex: /@gmail\.com$/ } },
            { items: { $exists: true } }
        ]
    });

    const filtered = complexOrders.foundDocuments.filter(order =>
        order.customer.email.includes('@gmail.com') || order.items.length >= 3
    );

    console.log(`Found ${filtered.length} orders`);
    filtered.forEach(order => {
        console.log(`- ${order.orderId}: ${order.items.length} items, ${order.customer.email}`);
    });

    // Complex filter 3: Pending or cancelled, not shipped, under $1000
    console.log('\n=== Pending/Cancelled, not shipped, under $1000 ===');
    const { data: pendingOrders } = await orders.find({
        status: { $in: ['pending', 'cancelled'] },
        shippedAt: null,
        total: { $lt: 1000 }
    });
    console.log(`Found ${pendingOrders.foundCount} orders`);
    pendingOrders.foundDocuments.forEach(order => {
        console.log(`- ${order.orderId}: ${order.status} - $${order.total}`);
    });

    // Complex filter 4: NOT cancelled AND (VIP OR total > $800)
    console.log('\n=== Active orders: VIP or high value ===');
    const { data: activeOrders } = await orders.find({
        status: { $ne: 'cancelled' },
        $or: [
            { 'customer.vip': true },
            { total: { $gte: 800 } }
        ]
    });
    console.log(`Found ${activeOrders.foundCount} orders`);
    activeOrders.foundDocuments.forEach(order => {
        console.log(`- ${order.orderId}: ${order.customer.name} (VIP: ${order.customer.vip}) - $${order.total}`);
    });

    // Complex filter 5: NOR query - exclude both cancelled and low-value orders
    console.log('\n=== Exclude cancelled AND orders under $200 ===');
    const { data: qualityOrders } = await orders.find({
        $nor: [
            { status: 'cancelled' },
            { total: { $lt: 200 } }
        ]
    });
    console.log(`Found ${qualityOrders.foundCount} orders`);
    qualityOrders.foundDocuments.forEach(order => {
        console.log(`- ${order.orderId}: ${order.status} - $${order.total}`);
    });

    await db.close();
}

advancedFiltering().catch(console.error);

Update Operations

Demonstrate various update operators including arrays and nested fields.

const LiekoDB = require('liekodb');

const db = new LiekoDB({
    storagePath: './storage',
    debug: true
});

const profiles = db.collection('profiles');

async function updateOperations() {
    // Insert initial profile
    console.log('=== Inserting profile ===');
    const { data: insertResult } = await profiles.insert({
        username: 'john_doe',
        email: 'john@example.com',
        stats: {
            loginCount: 0,
            lastLogin: null,
            points: 100
        },
        tags: ['new'],
        preferences: {
            theme: 'light',
            notifications: true
        }
    });

    const userId = insertResult.insertedIds[0];

    // $inc - Increment login count
    console.log('\n=== Incrementing login count ===');
    await profiles.updateById(userId, {
        $inc: { 'stats.loginCount': 1 },
        $set: { 'stats.lastLogin': new Date().toISOString() }
    });

    // $push - Add tags
    console.log('\n=== Adding tags ===');
    await profiles.updateById(userId, {
        $push: { tags: 'active' }
    });

    // $addToSet - Add tag without duplicates
    console.log('\n=== Adding unique tag ===');
    await profiles.updateById(userId, {
        $addToSet: { tags: 'verified' }
    });
    await profiles.updateById(userId, {
        $addToSet: { tags: 'verified' }  // Won't create duplicate
    });

    // Multiple operations
    console.log('\n=== Multiple updates ===');
    await profiles.updateById(userId, {
        $inc: { 'stats.points': 50, 'stats.loginCount': 1 },
        $set: { 'preferences.theme': 'dark' },
        $push: { tags: 'premium' }
    });

    // $pull - Remove tag
    console.log('\n=== Removing tag ===');
    await profiles.updateById(userId, {
        $pull: { tags: 'new' }
    });

    // Get final state
    const { data: finalProfile } = await profiles.findById(userId);
    console.log('\n=== Final profile ===');
    console.log(JSON.stringify(finalProfile, null, 2));

    await db.close();
}

updateOperations().catch(console.error);

Bulk Operations & Performance

Efficiently handle large datasets with bulk inserts and batch updates.

const LiekoDB = require('liekodb');

const db = new LiekoDB({
    storagePath: './storage',
    autoSaveInterval: 10000,
    debug: true
});

const analytics = db.collection('analytics');

async function bulkOperations() {
    console.log('=== Bulk Insert Performance Test ===');

    // Generate large dataset
    const events = [];
    const startTime = Date.now();

    for (let i = 1; i <= 10000; i++) {
        events.push({
            eventType: ['click', 'view', 'purchase', 'signup'][Math.floor(Math.random() * 4)],
            userId: `user_${Math.floor(Math.random() * 1000)}`,
            timestamp: new Date(Date.now() - Math.random() * 30 * 24 * 60 * 60 * 1000).toISOString(),
            value: Math.floor(Math.random() * 100),
            metadata: {
                device: ['mobile', 'desktop', 'tablet'][Math.floor(Math.random() * 3)],
                country: ['US', 'UK', 'FR', 'DE', 'JP'][Math.floor(Math.random() * 5)]
            }
        });
    }

    console.log(`Generated ${events.length} events in ${Date.now() - startTime}ms`);

    // Bulk insert
    const insertStart = Date.now();
    const { data: insertResult } = await analytics.insert(events);
    console.log(`Inserted ${insertResult.insertedCount} documents in ${Date.now() - insertStart}ms`);

    // Bulk update - mark recent purchases
    console.log('\n=== Bulk Update ===');
    const updateStart = Date.now();
    const recentDate = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();

    const { data: updateResult } = await analytics.update(
        {
            eventType: 'purchase',
            timestamp: { $gte: recentDate }
        },
        { $set: { processed: true } },
        { returnType: 'count' }
    );
    console.log(`Updated ${updateResult.updatedCount} documents in ${Date.now() - updateStart}ms`);

    // Aggregate queries
    console.log('\n=== Statistics ===');

    const { data: byType } = await analytics.find();
    const typeCount = {};
    byType.foundDocuments.forEach(event => {
        typeCount[event.eventType] = (typeCount[event.eventType] || 0) + 1;
    });
    console.log('Events by type:', typeCount);

    const { data: mobileUsers } = await analytics.find({
        'metadata.device': 'mobile',
        eventType: 'purchase'
    });
    console.log(`Mobile purchases: ${mobileUsers.foundCount}`);

    // Cleanup old events
    console.log('\n=== Cleanup ===');
    const oldDate = new Date(Date.now() - 60 * 24 * 60 * 60 * 1000).toISOString();
    const { data: deleteResult } = await analytics.delete({
        timestamp: { $lt: oldDate }
    });
    console.log(`Deleted ${deleteResult.deletedCount} old events`);

    const finalCount = await analytics.count();
    console.log(`Final count: ${finalCount.data} events`);

    await db.close();
}

bulkOperations().catch(console.error);

E-commerce Store Example

Complete example simulating an e-commerce system with products, orders, and inventory management.

const LiekoDB = require('liekodb');

const db = new LiekoDB({
    storagePath: './storage',
    debug: true
});

const products = db.collection('products');
const customers = db.collection('customers');
const orders = db.collection('orders');

async function ecommerceExample() {
    // Setup products
    console.log('=== Setting up products ===');
    await products.insert([
        { sku: 'LAPTOP-001', name: 'Pro Laptop', price: 1299.99, stock: 15, category: 'Electronics' },
        { sku: 'MOUSE-001', name: 'Wireless Mouse', price: 29.99, stock: 50, category: 'Accessories' },
        { sku: 'KEYBOARD-001', name: 'Mechanical Keyboard', price: 89.99, stock: 30, category: 'Accessories' },
        { sku: 'MONITOR-001', name: '4K Monitor', price: 449.99, stock: 20, category: 'Electronics' },
        { sku: 'HEADSET-001', name: 'Gaming Headset', price: 79.99, stock: 25, category: 'Accessories' }
    ]);

    // Register customers
    console.log('\n=== Registering customers ===');
    const { data: customer1 } = await customers.insert({
        name: 'Alice Johnson',
        email: 'alice@example.com',
        address: {
            street: '123 Main St',
            city: 'New York',
            country: 'US'
        },
        loyaltyPoints: 0,
        orders: []
    });

    const customerId = customer1.insertedIds[0];

    // Create order
    console.log('\n=== Creating order ===');
    const orderItems = [
        { sku: 'LAPTOP-001', quantity: 1, price: 1299.99 },
        { sku: 'MOUSE-001', quantity: 2, price: 29.99 }
    ];

    const orderTotal = orderItems.reduce((sum, item) =>
        sum + (item.price * item.quantity), 0
    );

    const { data: orderResult } = await orders.insert({
        customerId: customerId,
        items: orderItems,
        total: orderTotal,
        status: 'pending',
        shippingAddress: {
            street: '123 Main St',
            city: 'New York',
            country: 'US'
        }
    });

    const orderId = orderResult.insertedIds[0];

    // Update inventory
    console.log('\n=== Updating inventory ===');
    for (const item of orderItems) {
        await products.update(
            { sku: item.sku },
            { $inc: { stock: -item.quantity } }
        );
    }

    // Add loyalty points (10% of total)
    const pointsEarned = Math.floor(orderTotal * 0.1);
    await customers.updateById(customerId, {
        $inc: { loyaltyPoints: pointsEarned },
        $push: { orders: orderId }
    });

    // Process order
    console.log('\n=== Processing order ===');
    await orders.updateById(orderId, {
        $set: {
            status: 'shipped',
            shippedAt: new Date().toISOString()
        }
    });

    // Generate reports
    console.log('\n=== Sales Report ===');

    // Low stock products
    const { data: lowStock } = await products.find(
        { stock: { $lt: 20 } },
        { sort: { stock: 1 } }
    );
    console.log(`\nLow stock products (${lowStock.foundCount}):`);
    lowStock.foundDocuments.forEach(product => {
        console.log(`- ${product.name}: ${product.stock} units`);
    });

    // Customer summary
    const { data: customer } = await customers.findById(customerId);
    console.log(`\nCustomer: ${customer.name}`);
    console.log(`Loyalty Points: ${customer.loyaltyPoints}`);
    console.log(`Total Orders: ${customer.orders.length}`);

    // Orders by status
    const { data: pendingOrders } = await orders.count({ status: 'pending' });
    const { data: shippedOrders } = await orders.count({ status: 'shipped' });
    console.log(`\nOrders Summary:`);
    console.log(`- Pending: ${pendingOrders}`);
    console.log(`- Shipped: ${shippedOrders}`);

    await db.close();
}

ecommerceExample().catch(console.error);

Real-time Analytics Dashboard

Track user activity and generate real-time statistics.

const LiekoDB = require('liekodb');

const db = new LiekoDB({
    storagePath: './storage',
    debug: true
});

const sessions = db.collection('sessions');
const pageViews = db.collection('pageViews');

async function analyticsExample() {
    // Simulate user sessions
    console.log('=== Generating session data ===');

    const users = ['user_1', 'user_2', 'user_3', 'user_4', 'user_5'];
    const pages = ['/home', '/products', '/about', '/contact', '/checkout'];

    // Create sessions
    for (let i = 0; i < 20; i++) {
        const userId = users[Math.floor(Math.random() * users.length)];
        const startTime = new Date(Date.now() - Math.random() * 24 * 60 * 60 * 1000);
        const duration = Math.floor(Math.random() * 1800) + 60; // 1-30 min

        await sessions.insert({
            userId,
            startTime: startTime.toISOString(),
            endTime: new Date(startTime.getTime() + duration * 1000).toISOString(),
            duration,
            device: ['mobile', 'desktop'][Math.floor(Math.random() * 2)],
            browser: ['Chrome', 'Firefox', 'Safari'][Math.floor(Math.random() * 3)],
            pagesVisited: Math.floor(Math.random() * 10) + 1
        });
    }

    // Generate page views
    for (let i = 0; i < 100; i++) {
        await pageViews.insert({
            userId: users[Math.floor(Math.random() * users.length)],
            page: pages[Math.floor(Math.random() * pages.length)],
            timestamp: new Date(Date.now() - Math.random() * 24 * 60 * 60 * 1000).toISOString(),
            duration: Math.floor(Math.random() * 300) + 10
        });
    }

    // Analytics queries
    console.log('\n=== Dashboard Analytics ===');

    // Total sessions by device
    const { data: allSessions } = await sessions.find();
    const deviceStats = {};
    allSessions.foundDocuments.forEach(session => {
        deviceStats[session.device] = (deviceStats[session.device] || 0) + 1;
    });
    console.log('\nSessions by device:', deviceStats);

    // Active users (sessions in last hour)
    const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000).toISOString();
    const { data: recentSessions } = await sessions.find({
        startTime: { $gte: oneHourAgo }
    });
    const activeUsers = new Set(recentSessions.foundDocuments.map(s => s.userId));
    console.log(`\nActive users (last hour): ${activeUsers.size}`);

    // Average session duration
    const totalDuration = allSessions.foundDocuments.reduce((sum, s) => sum + s.duration, 0);
    const avgDuration = Math.floor(totalDuration / allSessions.foundCount);
    console.log(`Average session duration: ${Math.floor(avgDuration / 60)}m ${avgDuration % 60}s`);

    // Most visited pages
    const { data: allViews } = await pageViews.find();
    const pageStats = {};
    allViews.foundDocuments.forEach(view => {
        pageStats[view.page] = (pageStats[view.page] || 0) + 1;
    });

    console.log('\nMost visited pages:');
    Object.entries(pageStats)
        .sort((a, b) => b[1] - a[1])
        .forEach(([page, count]) => {
            console.log(`  ${page}: ${count} views`);
        });

    // Long sessions (> 10 minutes)
    const { data: longSessions } = await sessions.find({
        duration: { $gt: 600 }
    });
    console.log(`\nEngaged users (sessions > 10min): ${longSessions.foundCount}`);

    // Mobile vs Desktop engagement
    const { data: mobileSessions } = await sessions.find({ device: 'mobile' });
    const mobileAvg = mobileSessions.foundDocuments.reduce((sum, s) => sum + s.pagesVisited, 0)
        / mobileSessions.foundCount;

    const { data: desktopSessions } = await sessions.find({ device: 'desktop' });
    const desktopAvg = desktopSessions.foundDocuments.reduce((sum, s) => sum + s.pagesVisited, 0)
        / desktopSessions.foundCount;

    console.log(`\nAverage pages per session:`);
    console.log(`  Mobile: ${mobileAvg.toFixed(1)}`);
    console.log(`  Desktop: ${desktopAvg.toFixed(1)}`);

    await db.close();
}

analyticsExample().catch(console.error);
Running Examples: Make sure to install LiekoDB first with npm install liekodb, then save any example to a .js file and run with node filename.js