Skip to main content

8.0.0

When I created RxDB, two years ago, there where some things that I did not consider and other things that I just decided wrong. With the breaking version 8.0.0 I rewrote some parts of RxDB and changed the API a bit. The focus laid on better defaults and better performance.

disableKeyCompression by default​

Because the keyCompression was confusing and most users do not use it, it is now disabled by default. Also the naming was bad, so disableKeyCompression is now renamed to keyCompression which defaults to false.

collection() now only accepts a RxJsonSchema as schema​

In the past, it was allowed to set an RxSchema or an RxJsonSchema as schema-field when creating a collection. This was confusing and so it is now only allowed to use RxJsonSchema.

required fields have to be set via array​

In the past it was allowed to set a field as required by setting the boolean value required: true. This is against the json-schema-standard and will make problems when switching between different schema-validation-plugins. Therefore required fields must now be set via required: ['fieldOne', 'fieldTwo'].

Setters are only callable on temporary documents​

To be similar to mongoosejs, there was the possibility to set a documents value via myDoc.foo = 'bar' and later call myDoc.save() to persist these changes. But there was the problem that we have no weak pointers in javascript and therefore we have to store all document-instances in a cache to run change-events on them and make them 'reactive'. To save memory-space, we reuse the same documents when they are used multiple times. This made it hard to determine what happens when multiple parts of an application used the setters at the same time. Also there was an undefined behavior what should happen when a field is changed via setter and also via replication before save() was called.

  • myDoc.age = 50;, myDoc.set('age', 50); and myDoc.save() is no more allowed on non-temporary-documents
  • Instead, to change document-data, use RxDocument.atomicUpdate() or RxDocument.atomicSet() or RxDocument.update().
  • The following document-methods no longer exist: synced$, resync()

middleware-hooks contain plain json as first parameter and RxDocument as second​

When the middleware-hooks where created, the goal was to work equal then mongoose. But this is not possible because mongoose is more 'static' and its documents never change their attributes. RxDB is a reactive database and when the state on disc changes, the attributes of the document also change. This caused some undefined behavior especially with async middleware-hooks. To solve this, hooks now can only modify the plain data, not the RxDocument itself.

myCollection.preSave(function(data, rxDocument) {
// to set age to 50 before saving, change the first parameter
data.age = 50;
}, false);

multiInstance is now done via broadcast-channel​

Because the BroadcastChannel-API is not usable in all browsers and also not in NodeJs, multiInstance-communication was hard. The hacky workaround was to use a pseudo-socket and regularly check if an other instance has emitted a RxChangeEvent. This was expensive because even when the database did nothing, we wasted disk-IO and CPU by handling this.

To solve this waste, I spend one month creating a module that polyfills the broadcast-channel-api so it works on old browsers, new browsers and even NodeJs. This does not only waste less resources but also has a lower latency. Also the module is used by more projects than RxDB which allows use the fix bugs and improve performance together.

Set QueryChangeDetection via RxDatabase-option​

In the past, the QueryChangeDetection had to be enabled by importing the QueryChangeDetection and calling a function on it. This was strange and also did not allow to toggle the QueryChangeDetection on specific databases. Now we set the QueryChangeDetection by adding the boolean field queryChangeDetection: true when creating the database.

const db = await RxDB.create({
name: 'heroesdb',
adapter: 'idb',
queryChangeDetection: false // <- queryChangeDetection (optional, default: false)
});
console.dir(db);

Reuse an RxDocument-prototype per collection instead of adding getters/setters to each document​

Because the fields of an RxDocument are defined dynamically by the schema and we could not use the Proxy-Object because it is not supported in IE11, there was one workaround used: Each time a document is created, all getters and setters where applied on it. This was expensive and now we use a different approach. Once per collection, a custom RxDocument-prototype and constructor is created and each RxDocument of this collection is created with the constructor. This change is a rewrite internally and should not change anything for RxDB-users. If you use RxDB with vuejs, you might get some problems that can be fixed by upgrading vuejs to the latest version.

Rewritten the inMemory-plugin​

The inMemory-plugin was written with some wrong estimations. I rewrote it and added much more tests. Also awaitPersistence() can now be used to check if all writes have already been replicated into the parent collection. Also RxCollection.watchForChanges() got split out from the replication-plugin into its own watch-for-changes-plugin because it is used in the inMemory and the replication functionality.

Some comparisons​

(Tested with node 10.6.0 and the memory-adapter, lower is better)

Reproduce with npm run build:size and npm run test:performance

7.7.18.0.0
Bundle-Size (Webpack+minify+gzip)110 kb101.962 kb
Spawn 1000 databases with 5 collections each8744 ms9906 ms
insert 2000 documents8006 ms5781 ms
find 10.000 documents3202 ms1312 ms