AxarDB Documentation
High-performance NoSQL database server powered by a JavaScript-based query language
AxarDB is a NoSQL database server that works with JavaScript-based queries using the Jint JavaScript engine. It runs on ASP.NET Core 8.0.
- System Configuration (sysconfig): Server-wide settings (
memoryLimitPercentage,bulkStoreMaxCacheBytes,maxRecursionDepth,queryTimeoutMinutes,queuePollIntervalSeconds) can now be managed via thesysconfigcollection. - Sys-prefix Protection: Custom collections with names starting with
sysare now blocked to prevent conflicts with internal system infrastructure. - Bulk Query Memory Optimization: Bulk (JSONL) queries now use chunked processing with temporary lightweight indexes, keeping memory bounded by
bulkStoreMaxCacheByteseven for very large files. - Multi-Language UTF-8 HTTP Encoding: Full UTF-8 support for query string parameters, resolving encoding issues for non-Latin alphabets (Turkish, Arabic, Russian, Chinese, Japanese, etc.).
- Lazy Collection Directory Creation: Collection folders are generated only when the first write operation (
insert) occurs, preventing clutter from read-only checks on non-existent collections. - UUID v7 as Default ID Scheme: All collections (Standard, Memory, Bulk) now generate RFC 9562 compliant UUID v7 IDs by default. New query functions
guidv7(),guidv7(datetime), andguidv7CreatedAt(guid)are available in all script contexts. - Multi-Engine Benchmark Tool (compare.py): A Python-based benchmark measures AxarDB (db/memory/bulk) against PostgreSQL, MariaDB, and MongoDB. Generates an interactive Chart.js HTML report (
output.html) with per-operation timing, a "How many times faster is AxarDB (memory)?" speedup chart, and a feature comparison matrix. The tool automatically raisesqueryTimeoutMinutesto 30 minutes before running and awaits each queue job with a 300-second timeout to prevent false cancellations.
Core Features
📦 Collection Based
MongoDB-like structure. Automatic creation.
🔍 JavaScript Query
Data processing with native JS syntax.
⚡ High Performance
Lazy evaluation via PLINQ and strictly capped 40% RAM cache usage.
🧠 Memory Store
TTL-based temporary RAM-only storage for sessions and caching.
💾 Bulk Store
High-performance JSONL static storage with auto-reload and LRU caching.
📊 Monitoring
Real-time query metrics, memory usage, and cost tracing dashboard.
📄 CSV Engine
Convert lists of objects to CSV, or parse raw CSV strings instantly.
📊 Index Support
Performance with ASC/DESC sorting.
🔗 Join Operations
Joining multiple collections.
👁️ Views
Server-side stored queries.
⚡ Triggers
Automated scripts that respond automatically.
Data Reading
The db object is the entry point for all database operations.
// Find a single record (returns the first match)
var user = db.users.find(u => u.age > 18);
// List all matches (convert to array with toList())
var admins = db.users.findall(u => u.role == 'admin');
// Check if an item is in an array (Contains logic)
var targetCats = [66, 69, 74];
var myCats = db.categories.findall(x => x.rowNumber != null && x.rowNumber.includes(targetCats));
// Compare two arrays for exact equality (SequenceEqual logic)
var targetTags = ["developer", "senior"];
var matches = db.users.findall(x => x.tags.includes(targetTags));
// Get the entire collection
var allUsers = db.users.findall();
// Get the first record
var first = db.users.findall().first();
// Record count
var count = db.users.findall().count();
var adults = db.users.findall().count(u => u.age > 18);
// Distinct unique values
var roles = db.users.findall().distinct(u => u.role);
// Case-insensitive search
var devs = db.users.contains(x => x.title == "developer");
// Pagination (skip and take)
var page2 = db.users.findall().skip(10).take(10);
// Sorting (orderBy and orderByDesc)
var oldestFirst = db.users.findall().orderBy(u => u.age);
var youngestFirst = db.users.findall().orderByDesc(u => u.age);
// Min and Max values
var maxAge = db.users.findall().max(u => u.age);
var minAge = db.users.findall().min(u => u.age);
findall() returns a ResultSet. To convert it into a standard JavaScript array,
you can optionally call .toList().
Data Writing
insert
db.users.insert({
name: "Ahmet",
age: 25,
role: "developer"
});
update
// Update records that match the condition
db.users.update(u => u.name == "Ahmet", { age: 26 });
// Update via ResultSet
db.users.findall(u => u.inactive).update({ status: "archived" });
delete
// Delete Documents (Filtered)
db.users.findall(u => u.inactive == true).delete();
// Delete Entire Collection (RAM + Disk)
db.users.delete();
db.deleteCollection("users");
foreach
db.users.findall().foreach(user => {
console.log(user.name);
});
Memory Store (TTL-based Temporary Storage)
The memory object provides transient, high-speed RAM-only storage. Ideal for sessions, transient state, and cache tables. Data is never persisted to disk, and records expire after a specified TTL (Time-To-Live).
Key Features
- RAM-Only: Zero disk write overhead, providing maximum throughput.
- TTL Expiration: Supports automatic expiration with custom intervals (in hours). Defaults to 1 hour if not specified.
- Background Cleanup: Expired entries are evicted lazily on access and periodically via a background thread.
Usage Examples
// Insert with default TTL of 1 hour
memory.sessions.insert({ userId: "user_123", token: "xyz" });
// Insert with custom TTL (e.g. 2.5 hours)
memory.sessions.insert({ userId: "user_456" }, 2.5);
// Query active memory records
var active = memory.sessions.findall(s => s.token != null);
// Delete from memory
memory.sessions.findall(s => s.userId == "user_123").delete();
Bulk Store (JSONL for Large Static Datasets)
The bulk object allows fast read and write operations on large static datasets (e.g. zip codes, countries, log exports) stored as JSON Lines (JSONL) files in the Bulk/ folder.
Key Features
- High-Performance JSONL: Optimized for bulk loading and static lookups without server-level locks.
- LRU Memory Cache: Automatically caches records in memory up to a configurable byte budget (default: 50 MB), evicting the least recently used collections.
- Memory-Bounded Chunked Queries: Filtered queries on large Bulk collections use chunked processing with temporary lightweight indexes. Data is read line-by-line, keeping memory usage bounded by
bulkStoreMaxCacheBytes. - Auto-Reload & Watcher: Monitor changes to files on disk via a FileSystemWatcher to automatically refresh memory cache. Can also be reloaded manually.
Usage Examples
// Bulk insert an array of objects
bulk.countries.insert([
{ name: "Turkey", code: "TR" },
{ name: "Germany", code: "DE" }
]);
// Find record from bulk store (uses LRU Cache)
var tr = bulk.countries.find(c => c.code == "TR");
// Manually reload cache for a collection
bulk.reload("countries");
Join Operations
// Recommended: Join with Aliases
var result = db.join(
alias(db.users, "u"),
alias(db.orders, "o")
)
.where(x => x.u._id == x.o.userId);
// Default: Join with indexed properties (j1, j2...)
var data = db.join(db.products, db.categories).select(x => ({
name: x.j1.productName,
category: x.j2.categoryName
}));
UUID v7 Support
AxarDB uses native RFC 9562 compliant UUID v7 as its default _id generation strategy for all collections. This guarantees chronologically ordered, time-sortable IDs that enhance lookup speeds. Older UUID v4 keys are fully compatible and can coexist within the same collections.
Global Functions
| Function | Description | Example |
|---|---|---|
guidv7() |
Generates a new UUID v7 using current UTC time. | guidv7() |
guidv7(datetime) |
Generates a new UUID v7 using the specified ISO 8601 date string. | guidv7("2024-01-15T10:30:00Z") |
guidv7CreatedAt(id) |
Extracts the UTC creation timestamp from a valid UUID v7 string. Returns Date or null. |
guidv7CreatedAt(doc._id) |
guid() |
Generates a standard UUID v4. Maintained for legacy compatibility. | guid() |
Usage Example
// Query creation date of a document
var doc = db.products.find(p => p.name == "Super Phone 0");
if (doc) {
var createdTime = guidv7CreatedAt(doc._id);
console.log("Product created at: " + createdTime);
}
Creating Index
// ASC (default)
db.users.index(x => x.email);
// DESC sorting
db.users.index(x => x.createdAt, "DESC");
// Chaining
db.users.insert({...}).index(x => x.name);
Built-in Prototype Extensions & Case-Insensitive Search
AxarDB extends native JavaScript prototypes on every script execution to add powerful utility methods. It also provides two distinct methods for case-insensitive searching.
Case-Insensitive Search Mechanisms
Do not confuse these two mechanisms as they serve different purposes:
- Collection-Level
contains(Exact Match): Uses a case-insensitive wrapper so property access is case-insensitive, performing exact matching. - String Prototype
.contains(str)(Substring Search): Custom method injected into all string instances for case-insensitive substring matching.
// 1. Collection-Level exact match (case-insensitive properties)
var devs = db.users.contains(x => x.title == "developer");
// Matches "Developer", "DEVELOPER", "developer"
// 2. String Prototype case-insensitive substring search
var matches = bulk.postalcodes.findall(x => x.placeName.contains("esen"));
// Matches "Esenler", "ESENYURT", "Büyükçekmece" (contains "esen")
String Prototype Extensions
| Method | Description | Example |
|---|---|---|
.contains(str) |
Case-insensitive substring search. Turkish character aware. | "İstanbul".contains("istan") → true |
.startsWith(str) |
Case-insensitive prefix check. Turkish character aware. | "İZMİR".startsWith("izm") → true |
.toLowerCase() |
Turkish-aware lowercase conversion (handles İ → i, etc.). |
"İZMİR".toLowerCase() → "izmir" |
Array & Object Prototype Extensions
| Prototype | Method | Description | Example |
|---|---|---|---|
| Array | .count(predicate?) |
Counts matching elements, or returns array length if no predicate. | arr.count(x => x.age > 18) |
| Array | .distinct(selector?) |
Deduplicates array. Optional selector projects values first. | arr.distinct(x => x.role) |
| Array / Object | |
Converts resultsets/iterables to standard arrays. Identity on arrays. | db.users.findall() |
Views
Views are reusable queries stored on the server side in the Views/ folder.
Public View (Accessible to Everyone)
// Accessible via HTTP GET /views/activeUsers (No Auth required)
db.saveView("activeUsers", `
// @access public
return db.users.findall(u => u.active == true);
`);
Private View (Internal Use Only)
// Can only be called with db.view(), not accessible from HTTP
db.saveView("internalReport", `
// @access private
return db.orders.findall(o => o.status == "pending");
`);
View Usage
// Call internally
var result = db.view("activeUsers");
// Get view code
var code = db.getView("activeUsers");
// Access via HTTP (only public views)
// GET /views/activeUsers
•
// @access public → Accessible from outside via HTTP GET•
// @access private → Can only be used internally via db.view()
Triggers
Triggers are asynchronous scripts that run automatically by monitoring file changes in the
Data/ folder. They are stored in the Triggers/ folder.
Creating a Trigger
// saveTrigger(triggerName, targetCollection, scriptCode)
db.saveTrigger("userNotifier", "users", `
// @target users
console.log("User changed: " + event.documentId);
webhook("https://api.example.com/notify",
{ id: event.documentId, type: event.type },
{ "Authorization": "Bearer " + $API_TOKEN }
);
`);
@target Metadata
Determines which collection the trigger will react to changes in:
// Monitor changes only in the "orders" collection
// @target orders
// Monitor multiple collections
// @target users,orders,products
Event Object
event.type // "changed" | "created" | "deleted"
event.collection // Name of the changed collection
event.documentId // _id value of the changed document
event.timestamp // Server time (ISO format)
Event Types
- created - When a new document is added
- changed - When an existing document is updated
- deleted - When a document is deleted
trigger_logs/
folder.
Vaults (Secure Storage)
Secure key-value store in the sysvaults collection for API keys and constants.
// Add value to Vault
addVault("API_KEY", "sk-xxxx...");
addVault("SLACK_WEBHOOK", "https://hooks.slack.com/...");
// Use as $Key in queries
webhook($SLACK_WEBHOOK, { text: "Notification!" }, {});
sysvaults collection via db.sysvaults.insert() is disabled to prevent unauthorized configuration changes. You must use the addVault(key, value) function.
Webhooks
The webhook(url, data, headers) function is used to send HTTP POST requests to external
services.
Basic Usage
// Simple webhook (without headers)
webhook("https://api.example.com/notify", {
message: "New record added",
timestamp: new Date().toISOString()
}, {});
Usage with Headers
// With Bearer Token
webhook("https://api.example.com/data",
{ userId: 123, action: "update" },
{
"Authorization": "Bearer " + $API_TOKEN,
"Content-Type": "application/json"
}
);
// With API Key
webhook("https://api.stripe.com/v1/charges",
{ amount: 1000, currency: "usd" },
{ "X-API-Key": $STRIPE_KEY }
);
// Slack Webhook
webhook($SLACK_WEBHOOK,
{ text: "New order received!" },
{ "Content-Type": "application/json" }
);
External Databases
AxarDB can execute queries on external MySQL/MariaDB and PostgreSQL databases.
MySQL / MariaDB
var conn = "Server=localhost;Database=test;Uid=root;Pwd=pass;";
// Read data
var users = mysqlRead(conn, "SELECT * FROM users WHERE age > @age", { age: 18 });
// Execute command
var count = mysqlExec(conn, "UPDATE users SET active = 1 WHERE id = @id", { id: 5 });
PostgreSQL
var conn = "Host=localhost;Database=db;Username=pg;Password=pass";
// Read data
var data = pgsqlRead(conn, "SELECT * FROM public.logs WHERE type = @t", { t: 'error' });
// Execute command
var affected = pgsqlExec(conn, "DELETE FROM public.logs WHERE id = @id", { id: 10 });
Queue Operations
Schedule long-running tasks for background execution using queue().
// Simple background job
var jobId = queue("db.logs.insert({msg: 'Background task', time: guid()})");
// Job with parameters and priority
var highPriJob = queue(
"db.users.update(u => u.id == @id, { active: true })",
{ id: 123 },
{ priority: 1 }
);
sysqueue collection via db.sysqueue.insert() is disabled. You must use the queue() function to schedule background tasks.
Queue Schema (db.sysqueue)
All background tasks are recorded in the sysqueue collection with the following structure:
_id: Unique task ID (string)queryTemplate: Query script template to execute (string)parameters: Object containing values for template parameters (object)options: Execution settings (object)createdAt: Timestamp when the task was queued (datetime)executionTime: Timestamp when task execution started (datetime,nullif pending)completedAt: Timestamp when task execution fully finished (datetime,nullif pending/running)priority: Task priority level (integer)duration: Task execution time in milliseconds (long)successResult: Execution result on success (object,nullon failure)errorMessage: Error message on failure (string,nullon success)
Data Recovery (Fail-safe Backup)
Every state-changing operation (such as insert, update, delete, drop, saveView, deleteTrigger, etc.) across the db, bulk, and sys collections automatically generates a reverse query. For example, an insert operation will generate a corresponding delete() query to easily undo the addition.
These recovery queries are appended sequentially into a daily file located at backup_queries/YYYY-MM-DD.txt. If an accidental deletion or modification occurs, you can manually execute these queries to restore your data to its previous state.
System Configuration (sysconfig)
AxarDB uses the sysconfig system collection to manage server-wide configuration settings. Changes to this collection are stored on disk and applied the next time the server restarts.
Available Configuration Fields
| Field | Type | Default | Description |
|---|---|---|---|
memoryLimitPercentage |
double | 40 | Maximum percentage of total system RAM used for document caching (0-100) |
bulkStoreMaxCacheBytes |
long | 52428800 | Maximum bytes for Bulk Store LRU memory cache (default: 50 MB) |
maxRecursionDepth |
int | 10 | Maximum recursion depth for query operations to prevent infinite loops |
queryTimeoutMinutes |
int | 5 | Maximum execution time (in minutes) before a query is automatically cancelled |
queuePollIntervalSeconds |
double | 30 | Interval (in seconds) for the background queue processor polling cycle |
Updating Configuration
// Reading current config
var config = db.sysconfig.findall().first();
console.log("Memory limit: " + config.memoryLimitPercentage + "%");
// Updating settings (requires server restart to take effect)
db.sysconfig.findall().update({
memoryLimitPercentage: 60,
queryTimeoutMinutes: 10,
queuePollIntervalSeconds: 15
});
sysconfig collection take effect after a server restart. The management console displays a contextual banner only when you are actively working on the sysconfig collection.
System Collections Overview
AxarDB includes four system collections, each serving a critical infrastructure role:
| Collection | Purpose | Insert Restriction |
|---|---|---|
sysusers |
User accounts and credentials for Basic Authentication | Direct insert restricted |
sysvaults |
Secure key-value store for API keys and secrets | Must use addVault() |
sysconfig |
Server-wide configuration parameters | Direct insert blocked |
sysqueue |
Background task queue for deferred execution | Must use queue() |
syslogs |
Virtual read-only collection for querying system logs | Read-only (modifications prohibited) |
Reserved sys Prefix
Any collection name starting with sys is reserved for internal system use. Attempting to create, access, or insert into a custom collection with a sys prefix (e.g., db.sysnew) will throw an InvalidOperationException. This protection is enforced at multiple layers:
- Bridge Layer:
db.sysnew→ blocked byAxarDBBridge.TryGetMember - Engine Layer:
AxarDB("sysnew")→ blocked byDatabaseEngineconstructor binding - Collection Layer:
db.sysnew.insert(...)→ blocked byCollection.Insert
sysusers, sysqueue, sysvaults, sysconfig, and syslogs are the only allowed sys-prefixed collection names.
Real-time Monitoring Dashboard
AxarDB includes a built-in real-time monitoring dashboard accessible at /monitor or /monitoring.html. It provides a visual interface to monitor server performance, database activity, and active memory stores.
Dashboard Features
- Metrics Charts: Displays live time-series tracking of queries/min and RAM allocation.
- Database Logs: Shows a rolling log of the last 50 HTTP requests, including HTTP methods, endpoints, response statuses, and durations.
- Memory Collections: Inspects active TTL collections, indicating active counts and memory state.
- Cost Analytics: Tracks call counts, average, minimum, maximum durations, and error rates of Views, Triggers, and Background Queue Jobs.
HTTP API
| Endpoint | Method | Description | Auth |
|---|---|---|---|
/query |
POST | Execute JavaScript query | ✓ |
/collections |
GET | List collections | ✓ |
/collections/{name} |
DELETE | Delete collection (RAM + Disk) | ✓ |
/views/{name} |
GET | Run public view | @access |
/views/{name} |
DELETE | Delete view | ✓ |
/triggers/{name} |
DELETE | Delete trigger | ✓ |
Query Parameters
// POST /query?userName=John&userAge=30
db.users.insert({
name: @userName,
age: parseInt(@userAge)
});
Security
- Basic Authentication: Required for /query and /collections
- Default User:
unlocker / unlocker - Password Hashing: Supports both plain text and SHA256 hashed passwords in the
sysuserscollection. - Injection Protection: @param placeholders are securely bound
- Malicious Code Check: eval, Function are blocked
eval(, Function(,
script in parameters are rejected.
.NET SDK (C#)
Integrate AxarDB into your .NET applications using the official AxarDB SDK.
using AxarDB.Sdk;
// Initialize Client
using var client = new AxarClient("http://localhost:5000", "unlocker", "unlocker");
// Insert Document
await client.InsertAsync("users", new { Name = "John", Age = 30 });
// Query with Parameters
var script = "db.users.findall(u => u.name == @name)";
var users = await client.QueryAsync<List<User>>(script, new { name = "John" });
// Update Documents
await client.UpdateAsync("users", "u => u.name == 'John'", new { Age = 31 });
// Builder Pattern (Fluent API)
var count = await client.Collection<User>("users").Where("age", ">", 18).CountAsync();
var first = await client.Collection<User>("users").FirstAsync();
// View Management
await client.CreateViewAsync("ActiveUsers", "return db.users.findall(u => u.active)");
var list = await client.CallViewAsync<List<User>>("ActiveUsers");
var filtered = await client.CallViewAsync<List<User>>("myview", new { minAge = 18 });
// Vault Storage
await client.AddVaultAsync("MY_SECRET", "12345");
Python SDK
Interact with AxarDB programmatically from your Python scripts and services.
from axardb import AxarClient
# Initialize Client
client = AxarClient("http://localhost:5000", "unlocker", "unlocker")
# Insert Document
client.insert("users", {"name": "John", "age": 30})
# Query via Builder API
users = client.collection("users").where("age", ">", 20).to_list()
# Document Count
count = client.collection("users").count()
# Delete Documents
client.collection("users").where("age", "<", 18).delete()
# View Management
client.create_view("MyView", "return db.users.take(10)")
res = client.call_view("MyView")
res = client.call_view("MyView", {"minAge": 18})
CLI Tool
AxarDB includes a Command Line Interface (CLI) tool for executing scripts, importing data, and running database commands directly from your terminal.
Usage Examples
# Interactive query login
./AxarDB.Cli -s "db.users.count()"
# Executing script from file
./AxarDB.Cli -f query.js
# Fully automated CI/CD mode with credentials and output file
./AxarDB.Cli -u admin -p pass -f query.js -o result.json
# List collections on the server
./AxarDB.Cli --show-collections
# Direct document insertion
./AxarDB.Cli --insert users "{\"name\":\"Alice\"}"
By default, AxarDB allows all origins (
*). You can restrict allowed origins when starting the database server using the CLI parameter:
dotnet run -- --cors "http://localhost:3000,http://example.com"
Multi-Engine Benchmark Tool
AxarDB comes with a Python-based benchmark runner (compare.py) to test database throughput (CRUD operations, indexing, and queries) against PostgreSQL, MariaDB, and MongoDB under the same workloads.
Running the Benchmark
python compare.py
Technical Specifications
- Metrics Measured: Single and Bulk Insert times, Index Creation, Count (COUNT), filtered Query/Range searches, record Updates, and Deletes.
- Latency Tracing: Server-side execution times are captured via the
sysqueueStopwatch mechanism, excluding HTTP network payload overhead to measure clean database engine performance. - Timeout Configuration: To avoid cancellations during deep range searches or heavy bulk inserts, the benchmark script automatically raises the
queryTimeoutMinutesinsysconfigto 30 minutes, and waits up to 300 seconds for queue jobs. - Report Generation: Generates a clean interactive HTML output report (
output.html) with Chart.js line and bar charts tracking operation duration and total speedup comparisons.
Utility Functions
// Create unique ID (UUID v4)
var id = guid();
// Create unique ID (UUID v7) using current time
var idV7 = guidv7();
// Create unique ID (UUID v7) using specified datetime string
var customIdV7 = guidv7("2024-01-15T10:30:00Z");
// Extract creation date from UUID v7
var createdDate = guidv7CreatedAt(idV7);
// Write log to console (server console and logs/)
console.log("Message");
// Send webhook (url, data, headers)
webhook("https://api.example.com/hook",
{ data: "value" },
{ "Authorization": "Bearer token" }
);
// Add value to Vault
addVault("KEY_NAME", "value");
// List existing collections
var cols = showCollections();
// Schedule background job
var jobId = queue("db.logs.insert({ msg: @msg })", { msg: "Hello" }, { priority: 1 });
// Get list of indexes for a collection
var indexes = getIndexes("users");
// Create alias for joins
var userAlias = alias(db.users, "u");
// Create SHA256 hash
var hash = sha256("password");
// Create random string
var token = randomString(32);
// Parse CSV or Generate CSV
var parsed = csv("id,name\n1,john");
var strOut = csv([{id: 1, name: "john"}]);
// Deep copy object
var copy = deepcopy(original);
// HTTP GET request
var res = httpGet("https://api.example.com", { "Auth": "..." });
// OpenAI compatible LLM Client
var ai = openai(url, token);
// Add system message to LLM Client
ai.addSysMsg("You are a helpful assistant");
// Send message to LLM Client
var response = ai.msg("Hello", {}, null);
// AES Encryption / Decryption
var secret = encrypt("hello", "salt");
var plain = decrypt(secret, "salt");
// Hash functions (MD5)
var m = md5("test");
// Date manipulation
var nextWeek = addDays(new Date(), 7);
var later = addMinutes(new Date(), 15);
var hourLater = addHours(new Date(), 1);
// Converters & String Utilities
var str = toString(42);
var parts = split("a,b,c", ",");
var b64 = toBase64("text");
var txt = fromBase64(b64);
var num = toDecimal("10.5");
var json = toJson({a: 1});
// Randoms
var n = randomNumber(1, 100);
var d = randomDecimal("0.01", "99.99");