{"id":13800601,"url":"https://github.com/Kirlovon/AloeDB","last_synced_at":"2025-05-13T09:31:45.773Z","repository":{"id":41518602,"uuid":"277340002","full_name":"Kirlovon/aloedb","owner":"Kirlovon","description":"Light, Embeddable, NoSQL database for Deno 🦕","archived":false,"fork":false,"pushed_at":"2024-07-30T18:47:01.000Z","size":32848,"stargazers_count":143,"open_issues_count":4,"forks_count":12,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-05-08T20:55:21.565Z","etag":null,"topics":["data","database","datastore","db","deno","embeddable","embedded","embedded-database","javascript","json","light","nosql","nosql-database","typescript"],"latest_commit_sha":null,"homepage":"https://deno.land/x/aloedb","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Kirlovon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-07-05T16:23:20.000Z","updated_at":"2025-03-18T15:58:27.000Z","dependencies_parsed_at":"2024-07-30T22:53:14.517Z","dependency_job_id":null,"html_url":"https://github.com/Kirlovon/aloedb","commit_stats":{"total_commits":38,"total_committers":4,"mean_commits":9.5,"dds":0.07894736842105265,"last_synced_commit":"849b3260bbca9d45d3bd971c26ef7bb9a5b7bf2a"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kirlovon%2Faloedb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kirlovon%2Faloedb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kirlovon%2Faloedb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kirlovon%2Faloedb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Kirlovon","download_url":"https://codeload.github.com/Kirlovon/aloedb/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253913194,"owners_count":21983273,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data","database","datastore","db","deno","embeddable","embedded","embedded-database","javascript","json","light","nosql","nosql-database","typescript"],"created_at":"2024-08-04T00:01:14.131Z","updated_at":"2025-05-13T09:31:44.479Z","avatar_url":"https://github.com/Kirlovon.png","language":"TypeScript","funding_links":[],"categories":["Modules"],"sub_categories":["Database"],"readme":"\u003cp align=\"center\"\u003e\n\t\u003cimg src=\"https://raw.githubusercontent.com/Kirlovon/AloeDB/master/other/head.png\" alt=\"AloeDB Logo\" width=\"256\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\t\u003ch3 align=\"center\"\u003eAloeDB\u003c/h3\u003e\n\t\u003cp align=\"center\"\u003e\u003ci\u003eLight, Embeddable, NoSQL database for Deno\u003c/i\u003e\u003c/p\u003e\n\u003c/p\u003e\n\n\u003cbr\u003e\n\n## ✨ Features\n* 🎉 Simple to use API, similar to [MongoDB](https://www.mongodb.com/)!\n* 🚀 Optimized for a large number of operations.\n* ⚖ No dependencies, even without [std](https://deno.land/std)!\n* 📁 Stores data in readable JSON file.\n\n\u003cbr\u003e\n\n## 📦 Importing\n```typescript\nimport { Database } from 'https://deno.land/x/aloedb@0.9.0/mod.ts'\n```\n\n\u003cbr\u003e\n\n## 📖 Example\n```typescript\nimport { Database } from 'https://deno.land/x/aloedb@0.9.0/mod.ts';\n\n// Structure of stored documents\ninterface Film {\n    title: string;\n    year: number;\n    film: boolean;\n    genres: string[];\n    authors: { director: string };\n}\n\n// Initialization\nconst db = new Database\u003cFilm\u003e('./path/to/the/file.json');\n\n// Insert operations\nawait db.insertOne({\n    title: 'Drive',\n    year: 2012,\n    film: true,\n    genres: ['crime', 'drama', 'noir'],\n    authors: { director: 'Nicolas Winding Refn' }\n});\n\n// Search operations\nconst found = await db.findOne({ title: 'Drive', film: true });\n\n// Update operations\nawait db.updateOne({ title: 'Drive' }, { year: 2011 });\n\n// Delete operations\nawait db.deleteOne({ title: 'Drive' });\n```\n_P.S. You can find more examples [here](https://github.com/Kirlovon/AloeDB/tree/master/examples)!_\n\n\n\u003cbr\u003e\n\n## 🏃‍ Benchmarks\nThis database is not aimed at a heavily loaded backend, but its speed should be good enough for small APIs working with less than a million documents.\n\nTo give you an example, here is the speed of a database operations with *1000* documents:\n\n| Insertion     | Searching     | Updating      | Deleting      |\n| ------------- | ------------- | ------------- | ------------- |\n| 15k _ops/sec_ | 65k _ops/sec_ | 8k _ops/sec_  | 10k _ops/sec_ |\n\n\u003cbr\u003e\n\n## 📚 Guide\n\n### Initialization\n```typescript\nimport { Database } from 'https://deno.land/x/aloedb@0.9.0/mod.ts';\n\ninterface Schema {\n\tusername: string;\n\tpassword: string;\n}\n\nconst db = new Database\u003cSchema\u003e({\n\tpath: './data.json',\n\tpretty: true,\n\tautoload: true,\n\tautosave: true,\n\toptimize: true,\n\timmutable: true,\n\tvalidator: (document: any) =\u003e {}\n});\n```\nThe following fields are available for configuration:\n* `path` - Path to the database file. If undefined, data will be stored only in-memory. _(Default: undefined)_\n* `pretty` - Save data in easy-to-read format. _(Default: true)_\n* `autoload` - Automatically load the file synchronously when initializing the database. _(Default: true)_\n* `autosave` - Automatically save data to the file after inserting, updating and deleting documents.  _(Default: true)_\n* `optimize` - Optimize data writing. If enabled, the data will be written many times faster in case of a large number of operations.  _(Default: true)_\n* `immutable` - Automatically deeply clone all returned objects. _(Default: true)_\n* `validator` - Runtime documents validation function. If the document does not pass the validation, just throw the error.\n\nAlso, you can initialize the database in the following ways:\n```typescript\n// In-memory database\nconst db = new Database();\n```\n\n```typescript\n// Short notation, specifying the file path only\nconst db = new Database('./path/to/the/file.json');\n```\n\n\u003cbr\u003e\n\n### Typization\nAloeDB allows you to specify the schema of documents.\nBy doing this, you will get auto-completion and types validation. This is a **completely optional** feature that can make it easier for you to work with the database.\n\nJust specify an interface that contains only the types supported by the database _(strings, numbers, booleans, nulls, array, objects)_, and everything will works like magic! 🧙‍\n\n```typescript\n// Your schema\ninterface User {\n\tusername: string;\n\tpassword: string;\n}\n\n// Initialize a database with a specific schema\nconst db = new Database\u003cUser\u003e();\n\nawait db.insertOne({ username: 'bob', password: 'qwerty' }); // Ok 👌\nawait db.insertOne({ username: 'greg' }); // Error: Property 'password' is missing\n```\n\n\u003cbr\u003e\n\n### Inserting\nAloeDB is a document-oriented database, so you storing objects in it. The supported types are **Strings**, **Numbers**, **Booleans**, **Nulls**, **Arrays** \u0026 **Objects**.\n\nKeep in mind that data types such as **Date**, **Map**, **Set** and other complex types are not supported, and all fields with them will be deleted. Also, any blank documents will not be inserted.\n\n```typescript\nconst inserted = await db.insertOne({ text: 'Hey hey, im inserted!' });\nconsole.log(inserted); // { text: 'Hey hey, im inserted!' }\n```\n\n\u003cbr\u003e\n\n### Querying\nSearch query can be an object or a search function. If query is an object, then the search will be done by deeply comparing the fields values in the query with the fields values in the documents.\n\nIn search queries you can use **Primitives** _(strings, numbers, booleans, nulls)_, **Arrays**, **Objects**, **RegExps** and **Functions**.\n\n ```typescript\nawait db.insertMany([\n\t{ key: 1, value: 'one' },\n\t{ key: 2, value: 'two' },\n\t{ key: 3, value: 'three' },\n]);\n\n// Simple query\nconst found1 = await db.findOne({ key: 1 });\nconsole.log(found1); // { key: 1, value: 'one' }\n\n// Advanced query with search function\nconst found2 = await db.findOne((document: any) =\u003e document.key === 2);\nconsole.log(found2); // { key: 2, value: 'two' }\n```\n\nWhen specifying **Arrays** or **Objects**, a deep comparison will be performed.\n ```typescript\nawait db.insertMany([\n\t{ key: 1, values: [1, 2] },\n\t{ key: 2, values: [1, 2, 3] },\n\t{ key: 3, values: [1, 2, 3, 4] },\n]);\n\nconst found = await db.findOne({ values: [1, 2, 3] });\nconsole.log(found); // { key: 2, values: [1, 2, 3] }\n```\n\n\u003cbr\u003e\n\n### Updating\nAs with search queries, update queries can be either a function or an object. If this is a function, then the function receives the document to update as a parameter, and you must return updated document from the function. _(or return `null` or `{}` to delete it)_\n\nBy the way, you can pass a function as a parameter value in an object. This can be useful if you want to update a specific field in your document. Also, you can return `undefined`, to remove this field.\n\n ```typescript\nawait db.insertMany([\n\t{ key: 1, value: 'one' },\n\t{ key: 2, value: 'two' },\n\t{ key: 3, value: 'three' },\n]);\n\n// Simple update\nconst updated1 = await db.updateOne({ key: 1 }, { key: 4, value: 'four' });\nconsole.log(updated1); // { key: 4, value: 'four' }\n\n// Advanced update with update function\nconst updated2 = await db.updateOne({ key: 2 }, (document: any) =\u003e {\n\tdocument.key = 5;\n\tdocument.value = 'five';\n\treturn document;\n});\nconsole.log(updated2); // { key: 5, value: 'five' }\n\n// Advanced update with field update function\nconst updated3 = await db.updateOne({ key: 3 }, {\n\tkey: (value: any) =\u003e value === 6,\n\tvalue: (value: any) =\u003e value === 'six'\n});\nconsole.log(updated3); // { key: 6, value: 'six' }\n```\n\n\u003cbr\u003e\n\n## 🔧 Methods\n\n### Documents\n```typescript\ndb.documents;\n```\nThis property stores all your documents. It is better not to modify these property manually, as database methods do a bunch of checks for security and stability reasons. But, if you do this, be sure to call `await db.save()` method after your changes.\n\n\u003cbr\u003e\n\n### InsertOne\n```typescript\nawait db.insertOne({ foo: 'bar' });\n```\nInserts a document into the database. After insertion, it returns the inserted document.\n\nAll fields with `undefined` values will be deleted. Empty documents will not be inserted.\n\nBy default, the document will be inserted as the last entry in the database. To insert it somewhere else, specify the optional `index` parameter:\n\n```typescript\nawait db.insertOne({ foo: 'bar' }, 9);\n```\n\nIf the provided `index` is greater than the number of database entries, it will be inserted at the end.\n\n\u003cbr\u003e\n\n### InsertMany\n```typescript\nawait db.insertMany([{ foo: 'bar' }, { foo: 'baz' }]);\n```\nInserts multiple documents into the database. After insertion, it returns the array with inserted documents.\n\nThis operation is **atomic**, so if something goes wrong, nothing will be inserted.\n\n\u003cbr\u003e\n\n### FindOne\n```typescript\nawait db.findOne({ foo: 'bar' });\n```\nReturns a document that matches the search query. Returns `null` if nothing found.\n\n\u003cbr\u003e\n\n### FindMany\n```typescript\nawait db.findMany({ foo: 'bar' });\n```\nReturns an array of documents matching the search query.\n\n\u003cbr\u003e\n\n### UpdateOne\n```typescript\nawait db.updateOne({ foo: 'bar' }, { foo: 'baz' });\n```\nModifies an existing document that match search query. Returns the found document with applied modifications. If nothing is found, it will return `null`.\n\nThe document will be deleted if all of its fields are `undefined`, or if you return `null` or `{}` using a update function.\n\nThis operation is **atomic**, so if something goes wrong, nothing will be updated.\n\n\u003cbr\u003e\n\n### UpdateMany\n```typescript\nawait db.updateMany({ foo: 'bar' }, { foo: 'baz' });\n```\nModifies all documents that match search query. Returns an array with updated documents.\n\nThis operation is **atomic**, so if something goes wrong, nothing will be updated.\n\n\u003cbr\u003e\n\n### DeleteOne\n```typescript\nawait db.deleteOne({ foo: 'bar' });\n```\nDeletes first found document that matches the search query. After deletion, it will return deleted document.\n\n\u003cbr\u003e\n\n### DeleteMany\n```typescript\nawait db.deleteMany({ foo: 'bar' });\n```\nDeletes all documents that matches the search query. After deletion, it will return all deleted documents.\n\nThis operation is **atomic**, so if something goes wrong, nothing will be deleted.\n\n\u003cbr\u003e\n\n### Count\n```typescript\nawait db.count({ foo: 'bar' });\n```\nReturns the number of documents found by the search query. If the query is not specified or empty, it will return total number of documents in the database.\n\n\u003cbr\u003e\n\n### Drop\n```typescript\nawait db.drop();\n```\nRemoves all documents from the database.\n\n\u003cbr\u003e\n\n### Load\n```typescript\nawait db.load();\n```\nLoads, parses and validates documents from the specified database file. If the file is not specified, then nothing will be done.\n\n\u003cbr\u003e\n\n### LoadSync\n```typescript\ndb.loadSync();\n```\nSame as `db.load()` method, but synchronous. Will be called automatically if the `autoload` parameter is set to **true**.\n\n\u003cbr\u003e\n\n### Save\n```typescript\nawait db.save();\n```\nSaves documents from memory to a database file. If the `optimize` parameter is **false**, then the method execution will be completed when data writing is completely finished. Otherwise the data record will be added to the queue and executed later.\n\n\u003cbr\u003e\n\n### Helpers\nThis module contains helper functions that will make it easier to write and read search queries.\n\n ```typescript\n // Importing database \u0026 helpers\nimport { Database, and, includes, length, not, exists } from 'https://deno.land/x/aloedb@0.9.0/mod.ts';\n\nconst db = new Database();\nawait db.insertOne({ test: [1, 2, 3] });\n\n// Helpers usage\nconst found = await db.findOne({\n\ttest: and(\n\t\tlength(3),\n\t\tincludes(2)\n\t),\n\tother: not(exists())\n});\n\nconsole.log(found); // { test: [1, 2, 3] }\n```\n\n#### List of all available helpers:\n* moreThan\n* moreThanOrEqual\n* lessThan\n* lessThanOrEqual\n* between\n* betweenOrEqual\n* exists\n* type\n* includes\n* length\n* someElementMatch\n* everyElementMatch\n* and\n* or\n* not\n\n\u003cbr\u003e\n\n## 💡 Tips \u0026 Tricks\n\n### Multiple Collections\n\nBy default, one database instance has only one collection. However, since the database instances are quite lightweight, you can initialize multiple instances for each collection.\n\nKeep in mind that you **cannot specify the same file for multiple instances!**\n\n```typescript\nimport { Database } from 'https://deno.land/x/aloedb@0.9.0/mod.ts';\n\n// Initialize database instances\nconst users = new Database({ path: './users.json' });\nconst posts = new Database({ path: './posts.json' });\nconst comments = new Database({ path: './comments.json' });\n\n// For convenience, you can collect all instances into one object\nconst db = { users, posts, comments };\n\n// Looks nice 😎\nawait db.users.insertOne({ username: 'john', password: 'qwerty123' });\n```\n\n\u003cbr\u003e\n\n### Runtime Validation\n\nYou cannot always be sure about the data that comes to your server. TypeScript highlights a lot of errors at compilation time, but it doesn't help at runtime.\n\nLuckily, you can use a library such as [SuperStruct](https://github.com/ianstormtaylor/superstruct), which allows you to check your documents structure:\n\n```typescript\nimport { Database } from 'https://deno.land/x/aloedb@0.9.0/mod.ts';\nimport { assert, object, string, Infer } from 'https://cdn.skypack.dev/superstruct?dts';\n\n// Specify structure\nconst User = object({\n\tusername: string(),\n\tpassword: string()\n});\n\n// Create validation function\nconst UserValidator = (document: any) =\u003e assert(document, User);\n\n// Convert structure to TypeScript type\ntype UserSchema = Infer\u003ctypeof User\u003e;\n\n// Initialize\nconst db = new Database\u003cUserSchema\u003e({ validator: UserValidator });\n\n// Ok 👌\nawait db.insertOne({ username: 'bob', password: 'dylan' });\n\n// StructError: At path: password -- Expected a string, but received: null\nawait db.insertOne({ username: 'bob', password: null as any });\n```\n\n\u003cbr\u003e\n\n### Manual Changes\n\nFor performance reasons, a copy of the whole storage is kept in memory. Knowing this, you can modify the documents manually by modifying the `db.documents` parameter.\n\nMost of the time this is not necessary, as the built-in methods are sufficient, but if you want to have full control, you can do it!\n\nKeep in mind that after your changes, **you should always call the `await db.save()` method!**\n\n```typescript\nimport { Database } from 'https://deno.land/x/aloedb@0.9.0/mod.ts';\n\n// Initialize\nconst db = new Database('./data.json');\n\ntry {\n\n\t// Your changes...\n\tdb.documents.push({ foo: 'bar' });\n\n} finally {\n\tawait db.save(); // ALWAYS CALL SAVE!\n}\n```\n\nAlso, if you set the parameter **immutable** to `false` when initializing the database, you will get back references to in-memory documents instead of their copies. This means that you cannot change the returned documents without calling the `await db.save()` method.\n\n```typescript\nimport { Database } from 'https://deno.land/x/aloedb@0.9.0/mod.ts';\n\n// Initialization with immutability disabled\nconst db = new Database({ path: './data.json', immutable: false });\n\n// Initial data\nawait db.insertOne({ field: 'The Days' });\n\n// Finding and modifying document\nconst found = await db.findOne({ field: 'The Days' }) as { field: string };\nfound.field = 'The Nights';\n\n// Saving\nawait db.save();\n\nconsole.log(db.documents); // [{ field: 'The Nights' }]\n```\n\n\u003cbr\u003e\n\n## 🦄 Community Ports\nSurprisingly, this library was ported to other programming languages without my participation. **Much appreciation to this guys for their work!** ❤\n\n🔵 **[AlgoeDB](https://github.com/billykirk01/AlgoeDB)** - database for Go, made by [billykirk01](https://github.com/billykirk01)!\n\n🟠 **[AlroeDB](https://github.com/billykirk01/AlroeDB)** - database for Rust, also made by [billykirk01](https://github.com/billykirk01)!\n\n🟢 **[AloeDB-Node](https://github.com/wouterdebruijn/AloeDB-Node)** - port to the Node.js, made by [Wouter de Bruijn](https://github.com/wouterdebruijn)! _(With awesome Active Records example)_\n\n\u003cbr\u003e\n\n## 📃 License\nMIT _(see [LICENSE](https://github.com/Kirlovon/AloeDB/blob/master/LICENSE) file)_\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FKirlovon%2FAloeDB","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FKirlovon%2FAloeDB","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FKirlovon%2FAloeDB/lists"}