{"_rev":"36-67be14f36fdb8a35877410078cd59410","time":{"created":"2026-09-05T16:38:37.097Z","modified":"2026-09-05T16:38:37.523Z","1.0.0":"2025-07-31T01:12:24.769Z","1.0.1":"2025-07-31T01:31:06.782Z","1.0.2":"2025-07-31T01:45:26.573Z","1.0.3":"2025-07-31T03:17:22.899Z","1.0.4":"2025-07-31T14:13:03.522Z","1.0.5":"2025-07-31T14:47:04.977Z","1.0.6":"2025-07-31T20:27:12.640Z","1.0.7":"2025-07-31T22:21:54.883Z","1.0.8":"2025-08-01T01:26:13.056Z","1.0.9":"2025-08-01T02:48:53.045Z","1.0.10":"2025-08-02T14:34:33.646Z","1.0.11":"2025-08-02T15:21:23.655Z","1.0.12":"2025-08-02T22:34:21.918Z","0.0.2":"2025-11-30T00:51:45.168Z","0.1.0":"2025-11-30T02:37:58.372Z","0.0.1":"2025-12-01T03:43:23.485Z","0.0.3":"2025-12-15T02:00:43.384Z","0.0.4":"2025-12-15T13:15:34.848Z","0.1.1":"2025-12-20T20:51:01.810Z","0.1.2":"2026-01-05T13:41:51.562Z","0.1.3":"2026-01-05T15:04:13.266Z","0.1.4":"2026-01-06T15:17:07.231Z","0.1.5":"2026-01-08T04:25:54.760Z","0.1.6":"2026-02-01T10:45:47.998Z","0.1.7":"2026-02-02T04:09:06.242Z","0.1.8":"2026-07-17T00:09:57.472Z","0.1.9":"2026-07-24T22:42:00.866Z","0.1.91":"2026-08-05T13:12:50.178Z","0.1.92":"2026-08-10T17:43:04.486Z","1.0.20":"2026-09-05T16:38:37.298Z"},"_id":"liekodb","name":"liekodb","dist-tags":{"latest":"1.0.20"},"versions":{"1.0.20":{"name":"liekodb","version":"1.0.20","repository":{"type":"git","url":"git+https://github.com/Eih3/liekodb.git"},"homepage":"https://github.com/Eih3/liekodb","description":"Lightweight, MongoDB-like JSON database for Node.js","main":"liekodb.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"keywords":["database","json","local","file-based","mongodb","lightweight","nosql","offline","redis","cache"],"author":{"name":"Eih3 eih3.prog@gmail.com"},"contributors":[{"name":"emi.py"}],"license":"MIT","engines":{"node":">=24.0.0"},"gitHead":"86676827988c2665acb0060ae41362654567ee13","_id":"liekodb@1.0.20","bugs":{"url":"https://github.com/Eih3/liekodb/issues"},"_nodeVersion":"24.20.0","_npmVersion":"11.19.0","dist":{"integrity":"sha512-RNKh4TSa1D9SdQyzOE8Q1GSDLi1NX4LbCldZRUl8zQNiT80VwdlwypiJjK877ECyybYtiHGCPbQUU7R21gDLIA==","shasum":"201f39891b5944f564be00fdea91666965e5d241","tarball":"https://registry.npmjs.org/liekodb/-/liekodb-1.0.20.tgz","fileCount":4,"unpackedSize":137522,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQC8O2qfTvI9rfMpkQ7AAQsGIDKmR38jveRSzWNBLrXG5AIgK1iIuD2XLuWKtUDCAYYThwC6e9mDtffKTLu9u/ASF78="}]},"_npmUser":{"name":"eih3","email":"eih3.prog@gmail.com"},"directories":{},"maintainers":[{"name":"eih3","email":"eih3.prog@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/liekodb_1.0.20_1788626317169_0.6442360298898675"},"_hasShrinkwrap":false}},"maintainers":[{"name":"eih3","email":"eih3.prog@gmail.com"}],"description":"Lightweight, MongoDB-like JSON database for Node.js","homepage":"https://github.com/Eih3/liekodb","keywords":["database","json","local","file-based","mongodb","lightweight","nosql","offline","redis","cache"],"repository":{"type":"git","url":"git+https://github.com/Eih3/liekodb.git"},"contributors":[{"name":"emi.py"}],"author":{"name":"Eih3 eih3.prog@gmail.com"},"bugs":{"url":"https://github.com/Eih3/liekodb/issues"},"license":"MIT","readme":"# liekoDB\r\n\r\nA lightweight, MongoDB-like JSON database for Node.js and browser JS (with optional HTTP/REST API mode).\r\n\r\n## Key Features\r\n\r\n- **Parallel operations** with per-collection locking\r\n- **Intelligent LRU caching** — no eviction of actively used collections\r\n- **Atomic updates** with automatic persistence\r\n- **MongoDB-like query syntax** — `$gt`, `$in`, `$or`, `$regex`, etc.\r\n- **Batch operations** for insert, update, and delete\r\n- **Real-time events** — subscribe to database changes\r\n- **Lightweight** — zero external dependencies\r\n- **Debug mode** for easy troubleshooting\r\n\r\n## Table of Contents\r\n\r\n- [Introduction](#introduction)\r\n- [Installation](#installation)\r\n- [Configuration](#configuration)\r\n- [Insert Documents](#insert-documents)\r\n- [Find Documents](#find-documents)\r\n- [Update Documents](#update-documents)\r\n- [Count Documents](#count-documents)\r\n- [Delete Documents](#delete-documents)\r\n- [Filters & Operators](#filters--operators)\r\n- [Pagination](#pagination)\r\n- [Field Projection](#field-projection)\r\n- [Database Management](#database-management)\r\n- [Events](#events)\r\n- [Error Handling](#error-handling)\r\n- [Acknowledgments](#acknowledgments)\r\n\r\n## Introduction\r\n\r\nliekoDB is a fast, lightweight JSON database inspired by MongoDB. It supports two operation modes:\r\n\r\n- **Local Mode** — Store data in JSON files on your filesystem (Node.js only)\r\n- **HTTP Mode** — Connect to a remote liekoDB server using an HTTP client\r\n\r\n> **Note:** Local mode is only available in Node.js. Browser environments require HTTP mode with a token.\r\n\r\n> **HTTPAdapter is currently unavailable.** HTTP mode (remote server connections, browser usage) is not functional at this time. Only Local Mode is supported in the current version.\r\n\r\n## Installation\r\n\r\n### NPM\r\n\r\n```bash\r\nnpm install liekodb\r\n```\r\n\r\n### Yarn\r\n\r\n```bash\r\nyarn add liekodb\r\n```\r\n\r\n### Basic Usage\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('users')\r\n    .findById(1)\r\n    .then((user) => {\r\n        if (!user) return console.error('User not found');\r\n        console.log('User found: ', user);\r\n    })\r\n    .catch(e => console.error('Error while finding user: ', e));\r\n```\r\n\r\n## Configuration\r\n\r\n### Local Mode (Node.js)\r\n\r\n```javascript\r\nconst db = new liekoDB({\r\n  storagePath: './storage',         // Storage directory\r\n  autoSaveInterval: 5000,           // Auto-save every 5s\r\n  debug: true                       // Enable detailed logs\r\n});\r\n```\r\n\r\n### Local Mode Options\r\n\r\n| Option | Type | Default | Description |\r\n|---|---|---|---|\r\n| `debug` | boolean | `true` | Enable detailed logging |\r\n| `enableEvents` | boolean | `true` | Enable events |\r\n| `storagePath` | string | `'./storage'` | Directory for JSON files (Local mode) |\r\n| `autoSaveInterval` | number | `5000` | Auto-save interval in milliseconds |\r\n| `maxDocumentsReturn` | number | `100` | Max documents to return when using find/update methods |\r\n| `maxDocumentsInsert` | number | `100` | Max documents to insert when using insertMany method |\r\n| `maxEventDocuments` | number | `100` | Max documents to include in events |\r\n| `maxCollectionsCacheSize` | number | `20` | Max collections in cache |\r\n| `autoShutdown` | boolean | `true` | Auto-shutdown (flush & close) when received SIGINT signal |\r\n\r\n### HTTP Mode (Client)\r\n\r\n> HTTPAdapter is currently unavailable. The configuration below is documented for reference but is not functional in the current version.\r\n\r\n```javascript\r\nconst db = new liekoDB({\r\n  url: 'http://127.0.0.1:8050',\r\n  token: 'your-auth-token',       // Required for HTTP mode\r\n  poolSize: 10,                   // Connection pool size\r\n  timeout: 15000,                 // Request timeout (ms)\r\n  debug: true\r\n});\r\n```\r\n\r\n### HTTP Mode Options\r\n\r\n| Option | Type | Default | Description |\r\n|---|---|---|---|\r\n| `debug` | boolean | `false` | Enable detailed logging |\r\n| `url` | string | - | Remote database URL (HTTP mode) |\r\n| `token` | string | - | Authentication token (HTTP mode) |\r\n| `poolSize` | number | `10` | HTTP connection pool size |\r\n| `timeout` | number | `15000` | Request timeout in milliseconds |\r\n\r\n## Insert Documents\r\n\r\nAdd new documents to a collection. Supports single or bulk insertion with automatic ID generation.\r\n\r\n> Documents automatically receive `id`, `createdAt`, and `updatedAt` fields. If an `id` is provided, liekoDB will use it. Otherwise, it will generate a random one.\r\n\r\n### Insert Single Document\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('users')\r\n    .insertOne({\r\n        id: 1,\r\n        username: 'alice',\r\n        email: 'alice@example.com',\r\n        age: 28\r\n    })\r\n    .then((user) => {\r\n        if (!user) return console.error('User with this id already exists');\r\n        console.log('Inserted user: ', user);\r\n    })\r\n    .catch(e => console.error('Error while inserting user: ', e));\r\n```\r\n\r\n> `insertOne()` returns `null` on ID duplication.\r\n\r\n### Insert Multiple Documents\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('users')\r\n    .insertMany([\r\n        { id: '2', name: 'Bob', email: 'bob@example.com', age: 25 },\r\n        { id: '3', name: 'Charlie', email: 'charlie@example.com', age: 35 },\r\n        { id: '4', name: 'Homer', email: 'homer@example.com', age: 45 },\r\n        { id: '5', name: 'Marge', email: 'marge@example.com', age: 43 },\r\n        { id: '6', name: 'Lisa', email: 'lisa@example.com', age: 15 },\r\n        { id: '7', name: 'Bart', email: 'bart@example.com', age: 13 },\r\n        { id: '8', name: 'Maggie', email: 'maggie@example.com', age: 1 }\r\n    ], { returnDocuments: true })\r\n    .then((result) => {\r\n        if (result.skippedCount > 0) return console.error(`${result.skippedCount} users with these ids already exists`);\r\n        console.log('Inserted users: ', result.insertedDocuments);\r\n    })\r\n    .catch(e => console.error('Error while inserting users: ', e));\r\n```\r\n\r\n| Option | Type | Default | Description |\r\n|---|---|---|---|\r\n| `returnDocuments` | boolean | `false` | Return inserted documents into `insertedDocuments` |\r\n\r\n> Always check `skippedCount` to know how many documents were skipped due to ID conflicts.\r\n\r\n## Find Documents\r\n\r\nQuery documents with filters, sorting, and pagination.\r\n\r\n### Find by ID\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('users')\r\n    .findById(1)\r\n    .then((user) => {\r\n        if (!user) return console.error('User not found');\r\n        console.log('User found: ', user);\r\n    })\r\n    .catch(err => console.error('Error while finding user: ', err));\r\n```\r\n\r\n> `findById()` returns `null` if document not found.\r\n\r\n### Find One Document\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('users')\r\n    .findOne({ email: 'alice@example.com' })\r\n    .then((user) => {\r\n        if (!user) return console.error('User not found');\r\n        console.log('User found: ', user);\r\n    })\r\n    .catch(e => console.error('Error while finding user: ', e));\r\n```\r\n\r\n> `findOne()` returns `null` if document not found.\r\n\r\n### Find All Documents\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('users')\r\n    .find({})\r\n    .then(({ documents: users, pagination }) => {\r\n        console.log('All users: ', users);\r\n    })\r\n    .catch(e => console.error('Error while finding users: ', e));\r\n```\r\n\r\n> `find()` always returns `{ documents: [], pagination: {} }`.\r\n\r\n### Find with Filters\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('users')\r\n    .find(\r\n        { age: { $gte: 24 } },\r\n        {\r\n            sort: { age: -1 },\r\n            limit: 2,\r\n            fields: { id: 1, username: 1 }\r\n        })\r\n    .then(({ documents: users, pagination }) => {\r\n        console.log('All users: ', users);\r\n    })\r\n    .catch(e => console.error('Error while finding users: ', e));\r\n```\r\n\r\n| Option | Type | Methods | Description |\r\n|---|---|---|---|\r\n| `fields` | object | `findById`, `findOne`, `find` | Field projection (1 include, -1 exclude) |\r\n| `sort` | object | `findOne`, `find` | Sort results (1 ascending, -1 descending) |\r\n| `limit` | number | `find` | Limit returned documents |\r\n| `skip` | number | `find` | Number of documents to skip |\r\n| `page` | number | `find` | Page number (alternative to skip) |\r\n\r\n## Update Documents\r\n\r\nModify existing documents using update operators.\r\n\r\n### Update by ID\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('users')\r\n    .updateById(1, { $inc: { age: 1 } })\r\n    .then((updatedUser) => {\r\n        if (!updatedUser) return console.error('User not found');\r\n        console.log('Updated user: ', updatedUser);\r\n    })\r\n    .catch(e => console.error('Error while updating user: ', e));\r\n```\r\n\r\n> `updateById()` returns `null` if document not found.\r\n\r\n### Update One Document\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('users')\r\n    .updateOne({ email: 'alice@example.com' }, { lastLogin: Date.now() })\r\n    .then((updatedUser) => {\r\n        if (!updatedUser) return console.error('User not found');\r\n        console.log('Updated user: ', updatedUser);\r\n    })\r\n    .catch(e => console.error('Error while updating user: ', e));\r\n```\r\n\r\n> `updateOne()` returns `null` if no document matched the filters.\r\n\r\n### Update Multiple Documents\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('users')\r\n    .updateMany({ age: { $gte: 18 } }, { major: true }, { returnDocuments: true })\r\n    .then((result) => {\r\n        if (result.updatedCount === 0) return console.error('No users found to update');\r\n        console.log('Updated users: ', result.updatedDocuments);\r\n    })\r\n    .catch(e => console.error('Error while updating users: ', e));\r\n```\r\n\r\n| Option | Type | Default | Description |\r\n|---|---|---|---|\r\n| `returnDocuments` | boolean | `false` | Return updated documents into `updatedDocuments` |\r\n\r\n> Check `updatedCount` to know how many documents were updated.\r\n\r\n### Update Operators\r\n\r\n```javascript\r\nconst users = db.collection('users');\r\n\r\n// $set - Set a value\r\nawait users.updateOne({ email: 'alice@example.com' }, { $set: { verified: true } });\r\n// or simply with\r\nawait users.updateOne({ email: 'alice@example.com' }, { verified: true });\r\n\r\n// $inc - Increment\r\nawait users.updateOne({ email: 'alice@example.com' }, { $inc: { visits: 1 } });\r\n\r\n// $push - Add to array\r\nawait users.updateOne({ email: 'alice@example.com' }, { $push: { tags: 'premium' } });\r\n\r\n// $addToSet - Add without duplicates\r\nawait users.updateOne({ email: 'alice@example.com' }, { $addToSet: { roles: 'admin' } });\r\n\r\n// $pull - Remove from array\r\nawait users.updateOne({ email: 'alice@example.com' }, { $pull: { tags: 'banned' } });\r\n\r\n// $unset - Delete field\r\nawait users.updateOne({ email: 'alice@example.com' }, { $unset: { tempField: 1 } });\r\n```\r\n\r\n### Update Nested Fields\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('users')\r\n    .updateOne({ age: { $gte: 18 } }, { 'settings.language': 'en' })\r\n    .then((user) => {\r\n        if (!user) return console.error('User not found');\r\n        console.log('Updated user: ', user);\r\n    })\r\n    .catch(err => console.error('Error while updating user: ', err));\r\n```\r\n\r\n## Count Documents\r\n\r\nGet the number of documents matching a filter.\r\n\r\n### Count All Documents\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('users')\r\n    .count({})\r\n    .then((usersCount) => {\r\n        console.log('Users count: ', usersCount);\r\n    })\r\n    .catch(e => console.error('Error while counting users: ', e));\r\n```\r\n\r\n### Count with Filters\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('users')\r\n    .count({ age: { $gte: 28 } })\r\n    .then((usersCount) => {\r\n        console.log('Users count: ', usersCount);\r\n    })\r\n    .catch(e => console.error('Error while counting users: ', e));\r\n```\r\n\r\n## Delete Documents\r\n\r\nRemove documents from collections.\r\n\r\n### Delete by ID\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('users')\r\n    .deleteById(2)\r\n    .then((user) => {\r\n        if (!user) return console.error('User not found');\r\n        console.log('User with ID 2 successfully deleted.');\r\n    })\r\n    .catch(e => console.error('Error while deleting user: ', e));\r\n```\r\n\r\n> `deleteById()` returns `false` if document not found by ID.\r\n\r\n### Delete One Document\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('users')\r\n    .deleteOne({ email: 'bob@example.com' })\r\n    .then((deletedId) => {\r\n        if (!deletedId) return console.error('User not found');\r\n        console.log('User with email \"bob@example.com\" successfully deleted. Deleted ID :', deletedId);\r\n    })\r\n    .catch(e => console.error('Error while deleting user: ', e));\r\n```\r\n\r\n> `deleteOne()` returns `null` if no document matched the filters.\r\n\r\n### Delete Multiple by IDs\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('users')\r\n    .deleteMany({ id: { $in: [1, 5, 8] } })\r\n    .then((result) => {\r\n        if (result.deletedCount === 0) return console.error('No users found to delete');\r\n        if (result.deletedCount === 3) console.log(`All ${result.deletedCount} users deleted successfully`);\r\n        else console.error(`Only ${result.deletedCount} users were deleted`);\r\n    })\r\n    .catch(e => console.error('Error while deleting users: ', e));\r\n```\r\n\r\n> Check `deletedCount` to know how many documents were deleted.\r\n\r\n### Delete with Filters\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('users')\r\n    .deleteMany({ age: { $gte: 26 } })\r\n    .then((result) => {\r\n        if (result.deletedCount > 0) console.log(`Deleted ${result.deletedCount} users`);\r\n        else console.error('No users found to delete');\r\n    })\r\n    .catch(e => console.error('Error while deleting users: ', e));\r\n```\r\n\r\n## Filters & Operators\r\n\r\nliekoDB supports MongoDB-like query operators for filtering documents.\r\n\r\n### Complete Operators Reference\r\n\r\n| Operator | Category | Description | Example |\r\n|---|---|---|---|\r\n| `$eq` | Comparison | Matches values that are equal to a specified value | `{ age: { $eq: 25 } }` |\r\n| `$ne` | Comparison | Matches values that are not equal to a specified value | `{ status: { $ne: 'banned' } }` |\r\n| `$gt` | Comparison | Matches values that are greater than a specified value | `{ age: { $gt: 18 } }` |\r\n| `$gte` | Comparison | Matches values that are greater than or equal to a specified value | `{ age: { $gte: 18 } }` |\r\n| `$lt` | Comparison | Matches values that are less than a specified value | `{ age: { $lt: 65 } }` |\r\n| `$lte` | Comparison | Matches values that are less than or equal to a specified value | `{ age: { $lte: 65 } }` |\r\n| `$in` | Comparison | Matches any of the values specified in an array | `{ status: { $in: ['active', 'pending'] } }` |\r\n| `$nin` | Comparison | Matches none of the values specified in an array | `{ role: { $nin: ['admin', 'mod'] } }` |\r\n| `$and` | Logical | Joins query clauses with a logical AND | `{ $and: [{ age: { $gte: 18 } }, { status: 'active' }] }` |\r\n| `$or` | Logical | Joins query clauses with a logical OR | `{ $or: [{ role: 'admin' }, { role: 'mod' }] }` |\r\n| `$not` | Logical | Inverts the effect of a query expression | `{ age: { $not: { $lt: 18 } } }` |\r\n| `$nor` | Logical | Joins query clauses with a logical NOR | `{ $nor: [{ banned: true }, { deleted: true }] }` |\r\n| `$exists` | Element | Matches documents that have the specified field | `{ email: { $exists: true } }` |\r\n| `$regex` | Evaluation | Matches values that match a specified regular expression | `{ email: { $regex: /@gmail\\.com$/ } }` |\r\n| `$mod` | Evaluation | Performs a modulo operation on the value of a field | `{ age: { $mod: [2, 0] } }` |\r\n\r\n### Comparison Operators\r\n\r\n```javascript\r\nconst users = db.collection('users');\r\n\r\n// $eq - Equal\r\nawait users.find({ age: 25 });\r\nawait users.find({ age: { $eq: 25 } });\r\n\r\n// $ne - Not equal\r\nawait users.find({ status: { $ne: 'banned' } });\r\n\r\n// $gt, $gte, $lt, $lte - Greater/Less than\r\nawait users.find({ age: { $gte: 18, $lt: 65 } });\r\n\r\n// $in - In array\r\nawait users.find({ status: { $in: ['active', 'pending'] } });\r\n\r\n// $nin - Not in array\r\nawait users.find({ role: { $nin: ['admin', 'moderator'] } });\r\n```\r\n\r\n### Logical Operators\r\n\r\nBy default, multiple filter conditions separated by commas act as a logical AND. You only need `$and` for complex nested queries.\r\n\r\n```javascript\r\n// Implicit $and - Multiple conditions (recommended)\r\nawait users.find({ age: { $gte: 18 }, status: 'active' });\r\n\r\n// Explicit $and - Same result, more verbose\r\nawait users.find({\r\n  $and: [\r\n    { age: { $gte: 18 } },\r\n    { status: 'active' }\r\n  ]\r\n});\r\n\r\n// $or - At least one condition must match\r\nawait users.find({\r\n  $or: [\r\n    { role: 'admin' },\r\n    { role: 'moderator' }\r\n  ]\r\n});\r\n\r\n// $not - Negation\r\nawait users.find({ age: { $not: { $lt: 18 } } });\r\n\r\n// $nor - None of the conditions match\r\nawait users.find({\r\n  $nor: [\r\n    { banned: true },\r\n    { deleted: true }\r\n  ]\r\n});\r\n\r\n// Combining implicit AND with $or\r\nawait users.find({\r\n  status: 'active',  // Implicit AND\r\n  $or: [\r\n    { role: 'admin' },\r\n    { role: 'moderator' }\r\n  ]\r\n});\r\n```\r\n\r\n### Special Operators\r\n\r\n```javascript\r\n// $exists - Field exists\r\nawait users.find({ email: { $exists: true } });\r\n\r\n// $regex - Regular expression\r\nawait users.find({ email: { $regex: /@gmail\\.com$/ } });\r\n\r\n// $mod - Modulo operation (even ages)\r\nawait users.find({ age: { $mod: [2, 0] } });\r\n```\r\n\r\n### Array Queries\r\n\r\n```javascript\r\n// Match value in array\r\nawait users.find({ tags: 'premium' });\r\n\r\n// Match any value\r\nawait users.find({ tags: { $in: ['vip', 'premium'] } });\r\n```\r\n\r\n### Nested Fields (Dot Notation)\r\n\r\n```javascript\r\nawait users.find({ 'settings.theme': 'dark' });\r\n\r\nawait users.find({ 'address.city': 'Paris' });\r\n```\r\n\r\n## Pagination\r\n\r\nliekoDB provides flexible pagination with automatic metadata.\r\n\r\n### Basic Pagination\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\nconst productList = [];\r\nfor (let i = 1; i <= 50; i++) {\r\n    productList.push({\r\n        name: `Product ${i}`,\r\n        price: Math.floor(Math.random() * 1000) + 10,\r\n        category: ['Electronics', 'Clothing', 'Books', 'Home'][Math.floor(Math.random() * 4)],\r\n        stock: Math.floor(Math.random() * 100)\r\n    });\r\n}\r\n\r\ndb.collection('products').insertMany(productList)\r\n    .catch(e => { console.error('Error while inserting products: ', e); });\r\n\r\ndb.collection('products').find({}, { limit: 3, page: 4 })\r\n    .then(({ documents: products, pagination }) => {\r\n        console.log('All products : ', products);\r\n    })\r\n    .catch(e => { console.error('Error while finding products: ', e); });\r\n\r\ndb.collection('products')\r\n    .count({ category: { $in: ['Electronics', 'Books'] } })\r\n    .then((productsCount) => {\r\n        console.log('Products count in Electronics or Books category: ', productsCount);\r\n    })\r\n    .catch(e => console.error('Error while counting products: ', e));\r\n```\r\n\r\n### Using Skip\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('products').find({}, { limit: 2, skip: 40 })\r\n    .then(({ documents: products, pagination }) => {\r\n        console.log('All products : ', products);\r\n    })\r\n    .catch(e => { console.error('Error while finding products: ', e); });\r\n```\r\n\r\n## Field Projection\r\n\r\nSelect or exclude specific fields from query results.\r\n\r\n### Include Fields\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('products').find({}, { fields: { id: 1, name: 1, price: 1 } })\r\n    .then(({ documents: products, pagination }) => {\r\n        console.log('All products : ', products);\r\n    })\r\n    .catch(e => { console.error('Error while finding products: ', e); });\r\n```\r\n\r\n### Exclude Fields\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collection('products').find({}, { fields: { name: -1, price: -1 } })\r\n    .then(({ documents: products, pagination }) => {\r\n        console.log('All products : ', products);\r\n    })\r\n    .catch(e => { console.error('Error while finding products: ', e); });\r\n```\r\n\r\n> **Note:** Cannot mix inclusion and exclusion in the same projection.\r\n\r\n## Database Management\r\n\r\nManage collections and database status.\r\n\r\n### List Collections\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.listCollections()\r\n    .then(({ collections }) => { console.log('All collections: ', collections) });\r\n```\r\n\r\n### Get Collection Status\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.collectionStatus('users')\r\n    .then(console.log);\r\n\r\n// or\r\n\r\ndb.collection('users')\r\n    .status()\r\n    .then(console.log);\r\n```\r\n\r\n### Drop Collection\r\n\r\n```javascript\r\nconst liekoDB = require('liekodb');\r\n\r\nconst db = new liekoDB({\r\n    debug: true\r\n});\r\n\r\ndb.collection('users').drop()\r\n    .then(deleted => {\r\n        console.log(deleted);\r\n    })\r\n    .catch(e => { console.log('Error while dropping collection: ', e.message); });\r\n```\r\n\r\n### Close Database\r\n\r\n```javascript\r\ndb.close()\r\n    .then(() => { console.log('Database closed'); })\r\n    .catch(e => { console.log('Error while closing database: ', e.message); });\r\n\r\n// Flush all pending writes and close connections\r\n// By default, liekoDB auto close when script finish.\r\n// Use this method only if you want to close it before the end of the script.\r\n```\r\n\r\n## Events\r\n\r\nliekoDB can emit real-time events whenever documents are inserted, updated, deleted, or a collection is dropped. Subscribe with `db.subscribe()` to react to changes as they happen.\r\n\r\n> In Local Mode, events are emitted in-process. In HTTP Mode, events are streamed from the server over Server-Sent Events (SSE) — note that HTTPAdapter is currently unavailable (see [Introduction](#introduction)).\r\n\r\n> By default, events are enabled. Use `enableEvents: false` option to disable them.\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true, enableEvents: false });\r\n```\r\n\r\n### Subscribe to All Events\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.subscribe((event) => {\r\n    console.log('Event received: ', event);\r\n});\r\n```\r\n\r\n### Subscribe to Specific Collections\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.subscribe('users', (event) => {\r\n    console.log('Users collection event: ', event);\r\n});\r\n\r\n// Subscribe to all operations from multiple collections\r\ndb.subscribe(['users', 'orders'], (event) => {\r\n    console.log('Event: ', event);\r\n});\r\n```\r\n\r\n### Subscribe to Specific Operations\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\ndb.subscribe('users', 'insert', (event) => {\r\n    console.log('New user inserted: ', event);\r\n});\r\n\r\n// Subscribe to multiple operations for a collection\r\ndb.subscribe('users', ['insert', 'delete'], (event) => {\r\n    console.log('User inserted or deleted: ', event);\r\n});\r\n\r\n// Subscribe to all operations for multiple collections\r\ndb.subscribe(['users', 'orders'], '*', (event) => {\r\n    console.log('Event: ', event);\r\n});\r\n```\r\n\r\n> Allowed operations: `insert`, `update`, `delete`, `drop`, `*` (all).\r\n\r\n### Unsubscribe\r\n> Useless to unsubscribe when closing the nodejs application, that will automatically unsubscribe all the listeners.\r\n\r\n```javascript\r\nconst db = new (require('liekodb'))({ debug: true });\r\n\r\nconst unsubscribe = db.subscribe('users', (event) => {\r\n    console.log('Event: ', event);\r\n});\r\n\r\n// Later, stop listening\r\nunsubscribe();\r\n\r\n// Or, unsubscribe by reference\r\nconst listener = (event) => console.log('Event: ', event);\r\ndb.subscribe('users', listener);\r\ndb.unsubscribe(listener);\r\n```\r\n\r\n### Event Payload\r\n\r\n```javascript\r\n{\r\n  collection: 'users',\r\n  operation: 'insert',       // 'insert' | 'update' | 'delete' | 'drop'\r\n  emittedAt: 1719000000000,\r\n  method: 'insertOne',       // originating method, e.g. 'insertOne', 'updateMany', 'deleteById'\r\n  duration: 3,                // operation duration in ms\r\n  count: 1,                   // number of documents affected\r\n  ids: [1],                   // affected document ids\r\n  documents: [ /* ... */ ],   // affected documents (omitted if count exceeds maxEventDocuments)\r\n  truncated: false,           // true if documents were omitted due to maxEventDocuments\r\n  filters: { /* ... */ },     // present for update/delete operations\r\n  update: { /* ... */ }       // present for update operations ($set, $inc, etc.)\r\n}\r\n```\r\n\r\n> Use `maxEventDocuments` (default `100`) to control how many documents are included in the `documents` field before it gets truncated. See [Configuration](#configuration).\r\n\r\n## Error Handling\r\n\r\nAll operations throw a standardized response format.\r\n\r\n### Error Object Structure\r\n\r\n```javascript\r\n{\r\n  status: 400,\r\n  code: 'DB:QUERY_INVALID_OPERATOR',\r\n  message: 'Invalid filters query >> $gter <<',\r\n  details: {\r\n    suggestion: 'Check the operator name for typos',\r\n    received: '$gter',\r\n    allowedOps: [\r\n      '$eq',     '$ne',\r\n      '$gt',     '$gte',\r\n      '$lt',     '$lte',\r\n      '$in',     '$nin',\r\n      '$exists', '$regex',\r\n      '$and',    '$or',\r\n      '$nor',    '$not',\r\n      '$mod'\r\n    ]\r\n  }\r\n}\r\n\r\n{\r\n  status: 400,\r\n  code: 'DB:QUERY_INVALID_OPTION',\r\n  message: 'Invalid query option >> fieldss <<',\r\n  details: { received: 'fieldss', allowedOps: [ 'sort', 'fields' ] }\r\n}\r\n\r\n{\r\n  status: 400,\r\n  code: 'DB:UPDATE_INVALID_OPERATOR',\r\n  message: 'Invalid update operator >> $include <<',\r\n  details: {\r\n    allowedOps: [ '$set', '$unset', '$inc', '$push', '$pull', '$addToSet' ],\r\n    received: '$include'\r\n  }\r\n}\r\n\r\n{\r\n  status: 400,\r\n  code: 'DB:DOCUMENT_ID_REQUIRED',\r\n  message: 'updateById operation requires a valid document ID.'\r\n}\r\n```\r\n\r\n## Acknowledgments\r\n\r\nA heartfelt thank you to **emi.py** for his dedicated testing and debugging efforts. His work was instrumental in identifying and fixing critical issues related to:\r\n\r\n- Parallel operations across multiple collections\r\n- Cache eviction during active operations\r\n- Collection name handling in concurrent requests\r\n- Overall stability and performance improvements\r\n\r\nliekoDB is more reliable thanks to his contributions.\r\n\r\n---\r\n\r\n**liekoDB** — Lightweight. Reliable. Tested with passion. 💙\r\n","readmeFilename":"README.md"}