Changelog
Every SorlaDB release, from the first version in 2024 to today: what was added, what changed and what was fixed.
Technical changelog on GitHub ↗Complete documentation
A full guide in English and Brazilian Portuguese: 16 chapters, from the first five minutes to performance, testing and a cookbook. No code changes.
Documentation
- 16 chapters in English and Brazilian Portuguese: getting started, databases and collections, inserting, querying, cursors, updating and deleting, schema validation, forms, events, live queries, server sync, the console, TypeScript, performance, testing and a cookbook with FAQ.
Faster updates and custom stream handling
Updates copy only what changed, and streams can hand each block to your own code.
Added
stream(url, { apply(type, data) })hands each block to your code instead of writing it to a collection, andsorla.stream(url, { apply })works without a collection, for components that store rows themselves, like a data grid.
Performance
- Updates copy only the objects along the changed paths; the untouched parts are shared with the previous version, and stored data is never changed in place. A
bulkWriteof 100,000$setby_idwent from about 650 ms to 180 ms. - Change event payloads (
documents,previous) are copied only when someone listens. - Comparing the previous and new version of a document skips the shared parts instead of serializing both to JSON.
- Numbers, strings and booleans no longer go through
structuredClone.
Live queries and framework bindings
Queries that stay current on their own, with ready-made hooks for React, Vue, Svelte and Angular.
Added
collection.watch(query, options): live queries withsubscribe()/getSnapshot(), frozen copies, incremental updates (only changed documents are copied), one notification per batch of writes, and watching only while subscribed. It is also a Svelte store and an Observable for RxJSfrom().- Optional framework bindings, with types:
sorla-db/react(useQuery,useDocument),sorla-db/vue(useQuery),sorla-db/svelte(query,documentStore) andsorla-db/angular(querySignal,documentSignal).
Bulk writes, an _id index and server sync
MongoDB-style bulkWrite, instant lookups by _id, and loading from a backend over Server-Sent Events or WebSocket.
⚠ Attention when upgrading
Added
collection.bulkWrite(operations, { ordered })withinsertOne,updateOne,updateMany,replaceOne,deleteOneanddeleteMany: MongoDB counts and ids, one change event per type at the end, andBulkWriteErrorwithwriteErrorsand the partialresult.- An
_idindex: filters on_id({ _id: x },$eq,$in) find documents without scanning, infind,findOne,count, updates,replaceOne, deletes andbulkWrite. sort(spec, { nulls: 'first' | 'last' }), and collection options:createCollection(name, schema, { nulls }),setOptions()andgetOptions().cursor.ids(),cursor.forEach()andfor...ofiteration over copies.collection.stream(url, options): rows loaded in blocks from a Server-Sent Events endpoint, with custom headers and POST, reconnection withLast-Event-ID, upserts by_id, and progress and error callbacks.collection.connect(url, options)andsorla.connect(url, options): WebSocket requests and replies (load()pages,request()), pushedrows/ops/deleteapplied to the collection, queued requests while connecting, reconnection with back off, heartbeats and timeouts.sorla.readEventStream(body, onEvent), the text/event-stream parser, and regular expressions inside$in/$nin.
Changed
- Missing and null values sort last in both directions by default (they came first in ascending order, as in MongoDB). Use
{ nulls: 'first' }per sort or per collection to keep the previous order. find()no longer copies every matching document: the cursor copies a document only when it is read, and it is a snapshot of the momentfind()ran. Results are the same copies as before.
Inserts at scale
Inserting 100,000 documents went from minutes to well under a second.
Fixed
- Inserts were quadratic: every inserted document re-read the ids of the whole collection, so
insertManyof 100,000 documents took minutes. The ids are now read once per call, and a performance test guards it.
Forms bound to collections
Insert and edit documents with a plain HTML form, validated by the collection schema.
Added
collection.bindForm(form, options): insert or update mode, values converted with the schema, errors next to each field, validation as fields are left,generate: trueto build the fields from the schema,sorla:saved/sorla:invalidevents, and a controller withvalues,fill,validate,submit,load,resetanddestroy.collection.applyDefaults(doc): a copy of a document with the schema defaults.- A complete form example:
example/form_example.html.
Schema validation
Collections can enforce a JSON Schema on every insert, update and upsert, with clear errors per field.
Added
- Schema validation with a subset of JSON Schema:
type(plusdate),required,properties,additionalProperties,enum,const, numeric ranges,minLength/maxLength/pattern/format(email, date, date-time, uri),items/minItems/maxItems/uniqueItems, anddefault. Function schemas work too. sorla.ValidationErrorwitherrors: [{ path, rule, message }].collection.validate(doc),collection.setSchema(schema)andcollection.getSchema().
Fixed
- The schema given to
createCollection(name, schema)was never stored.
Updates, deletes and change events
The full write side of the MongoDB API, plus events to react to every change.
Added
updateOne/updateManywith$set,$unset,$inc,$push(with$each) and$pull,"a.b"paths and{ upsert }.replaceOne,deleteOne,deleteManyandcount(query).- Change events:
collection.on,onceandoffforinsert,update,replace,deleteandchange. - Query operators
$regex(with$options, or a RegExp value) and$exists. cursor.skip()andcursor.limit(), and inclusion projection ({ name: 1 }).- Database management:
sorla.listDatabases(),sorla.dropDb(),db.listCollections(),db.getCollection(),db.dropCollection()anddb.getStats(). - Type declarations for all of the above.
Changed
cursor.projection()returns the cursor and throws on invalid projections.
Solid foundations and an npm package
A long list of fixes, MongoDB-compatible sorting, TypeScript types, and a browser bundle that went from 1.6 MB to 9.5 kB.
⚠ Attention when upgrading
Added
insertOnereturns the inserted_idandinsertManyreturns the ids; callbacks receive them too.insertManyvalidates the whole batch before inserting anything.sort()follows MongoDB’s order across types, supports"a.b"paths and acollationoption, and returns the cursor.require('sorla-db')andimport sorla from 'sorla-db'both work, with TypeScript declarations.- Tests run on GitHub Actions on Node 18, 20, 22 and 24.
Changed
insertOnestores a copy: the given object no longer receives_idand is no longer linked to the stored document. Use the returned id.last()returns the document data, likefirst().- The browser bundle no longer includes faker: from 1.6 MB to 9.5 kB. The npm package ships only the library.
- Node 18 or later is required.
Fixed
cursor.sort()works (it always threw because of circular requires), andtoArray()returns plain copies.insertOneacceptsnullvalues and rejectsinsertOne(null); a duplicated_idis rejected.- Every nested object and array item is checked for prohibited keys, not just the first object.
findOne()returnsnullwhen nothing matches, andfirst()/last()returnnullon an empty cursor."a.b"paths returnundefinedwhen a step is missing instead of the parent object.- Changing a field of a stored document throws a clear error, documents work with symbol keys, and nothing is printed to the console anymore.
Nested logical operators
Combine $and, $or and $nor at any depth, with several operators per field.
Added
- Nested logical operators:
$and,$orand$norat any depth. - Several operators per field, at the top level and inside logical operators.
Changed
- A document without the queried field matches
$neand$nin, like MongoDB.
Fixed
- Nested
$and/$orthrewthis[operator] is not a function. - Only the first operator of a field was evaluated inside
$and/$or. $notnegates the whole condition.nullvalues can be used in query conditions.
First release
The first version of SorlaDB: in-memory collections in the browser, queried with the MongoDB language. Started in 2023 by Anderson Arruda.
Added
- Databases and collections:
createDb,useDbandcreateCollection, with documents stored in memory. insertOneandinsertMany.findandfindOnereturning a cursor withfirst(),last(),toArray(),hasNext()andnext().- Comparison operators
$eq,$ne,$gt,$gte,$lt,$lte,$inand$nin. - Logical operators
$and,$orand$not, which stop evaluating as soon as the result is known. - Dot paths to query nested objects (
"address.city") and field projection. - Keys with
$or.are rejected, because those characters are reserved for operators and paths. - A minified browser build that registers
window.sorla.
