# mongo-light A lightweight, embedded MongoDB-compatible document database written in Zig 0.16. Like SQLite, it stores everything in a single file; unlike SQLite, it speaks the MongoDB wire protocol, so real clients — `mongosh`, the Node.js driver, PyMongo — connect over TCP and just work. ## Quick start ```sh zig build # build the server zig build test # run the unit test suite zig-out/bin/mongo-light --port 27017 --db data.log # in another terminal: mongosh --port 27017 > db.users.insertOne({name: "alice", age: 30}) > db.users.find({age: {$gt: 25}}).toArray() > db.users.updateOne({name: "alice"}, {$set: {vip: true}}) > db.users.deleteOne({name: "bob"}) ``` ## Features - **Wire protocol**: OP_MSG (2013) plus legacy OP_QUERY/OP_REPLY (2004/2001) for the driver handshake; hello/isMaster with `maxWireVersion: 8`, so modern drivers (Node, Python, mongosh) connect without workarounds. - **BSON**: full parse/serialize round-trip for all common types (including binary, regex, timestamps, ObjectId), canonical MongoDB comparison order for sorting and range queries. - **CRUD**: `insert`, `find` (filter, sort, skip/limit, projection), `update` (multi/upsert), `delete`, `findAndModify`, `count`, `aggregate` (`$match`, `$sort`, `$skip`, `$limit`, `$project`, `$count`, `$group` with `$sum`), plus `create`/`drop`/`listCollections`/ `listDatabases`/`dropDatabase`. - **Query operators**: `$eq` `$ne` `$gt` `$gte` `$lt` `$lte` `$in` `$nin` `$exists` `$regex` (hand-rolled engine: anchors, `.`, `* + ?`, character classes, groups, alternation, `i`/`s` options) `$not` `$and` `$or` `$nor` `$size` `$all` `$elemMatch`, with dot paths and array multikey semantics. - **Update operators**: `$set` `$unset` `$inc` `$push` (`$each`) `$pull` `$rename`, with dot-path creation (including array indices). - **Storage**: append-only record log (CRC32-checked, `fsync` per write, torn-tail tolerant) with in-memory indexes rebuilt on open and automatic compaction (rewrite + atomic rename when the log grows past 16 MB). Killed mid-write (`kill -9`), the database recovers all committed writes; the log and compaction both work with relative or absolute `--db` paths. Records up to the announced 16 MB `maxBsonObjectSize` replay correctly. - **Concurrency**: a writer-preferring read/write lock splits command execution — reads (`find`, `count`, `aggregate`, `list*`) run concurrently across connections, writes (CRUD, DDL) are exclusive and totally ordered, and handshake/no-op commands run lock-free. The log append + `fsync` still happen under the write lock, so the crash guarantees are unchanged. Fine for light workloads. ## Layout ``` src/ bson.zig BSON parse/serialize, ObjectId, canonical comparison order wire.zig OP_MSG/OP_QUERY framing, message + reply builders commands.zig command dispatch (hello, CRUD, aggregate, admin) server.zig TCP accept loop, per-connection handlers db.zig in-memory engine: db → collection → _id → document maps storage.zig append-only log: records, replay, CRC validation query.zig filter matcher, regex engine, sort, projection update.zig update operators with dot-path navigation main.zig CLI: --port, --bind, --db ``` ## Not (yet) implemented - Authentication (SCRAM) — run without credentials - Real cursors (all results are returned in one batch, cursor id 0) - Indexes (O(n) scans) - Transactions, change streams, replicasets - Compression (OP_COMPRESSED) ## Code style Zig 0.16 idioms (`std.Io` threaded through everything, unmanaged containers); user-declared functions use `snake_case` per this repo's house style.