RxStorage
RxDB is not a self contained database. Instead the data is stored in an implementation of the RxStorage interface. This allows you to switch out the underlying data layer, depending on the JavaScript environment and performance requirements. For example you can use the SQLite storage for a capacitor app or you can use the Dexie.js RxStorage to store data in IndexedDB in a browser based application. There are also storages for other JavaScript runtimes like Node.js, React-Native, NativeScript and more.
Quick Recommendations
- In the Browser: Use the IndexedDB RxStorage if you have 👑 premium access, otherwise use the Dexie.js storage.
- In Electron and ReactNative: Use the SQLite RxStorage if you have 👑 premium access, otherwise use the LokiJS storage.
- In Capacitor: Use the SQLite RxStorage if you have 👑 premium access, otherwise use the Dexie.js storage.
Configuration Examples
The RxStorage layer of RxDB is very flexible. Here are some examples on how to configure more complex settings:
Storing much data in a browser securely
Lets say you build a browser app that needs to store a big amount of data as secure as possible. Here we can use a combination of the storages (encryption, IndexedDB, compression, schema-checks) that increase security and reduce the stored data size.
We use the schema-validation on the top level to ensure schema-errors are clearly readable and do not contain encrypted/compressed data. The encryption is used inside of the compression because encryption of compressed data is more efficient.
import { wrappedValidateAjvStorage } from 'rxdb/plugins/validate-ajv';
import { wrappedKeyCompressionStorage } from 'rxdb/plugins/key-compression';
import { wrappedKeyEncryptionCryptoJsStorage } from 'rxdb/plugins/encryption-crypto-js';
import { getRxStorageIndexedDB } from 'rxdb-premium/plugins/storage-indexeddb';
const myDatabase = await createRxDatabase({
storage: wrappedValidateAjvStorage({
storage: wrappedKeyCompressionStorage({
storage: wrappedKeyEncryptionCryptoJsStorage({
storage: getRxStorageIndexedDB()
})
})
})
});
High query Load
Also we can utilize a combination of storages to create a database that is optimized to run complex queries on the data really fast. Here we use the shardingstorage together with the worker storage. This allows to run queries in parallel multithreading instead of a single JavaScript process. Because the worker initialization can slow down the initial page load, we also use the localstorage-meta-optimizer to improve initialization time.
import { getRxStorageSharding } from 'rxdb-premium/plugins/storage-sharding';
import { getRxStorageWorker } from 'rxdb-premium/plugins/storage-worker';
import { getRxStorageIndexedDB } from 'rxdb-premium/plugins/storage-indexeddb';
import { getLocalstorageMetaOptimizerRxStorage } from 'rxdb-premium/plugins/storage-localstorage-meta-optimizer';
const myDatabase = await createRxDatabase({
storage: getLocalstorageMetaOptimizerRxStorage({
storage: getRxStorageSharding({
storage: getRxStorageWorker({
workerInput: 'path/to/worker.js',
storage: getRxStorageIndexedDB()
})
})
})
});
Low Latency on Writes and Simple Reads
Here we create a storage configuration that is optimized to have a low latency on simple reads and writes. It uses the memory-synced storage to fetch and store data in memory. For persistence the OPFS storage is used in the main thread which has lower latency for fetching big chunks of data when at initialization the data is loaded from disc into memory. We do not use workers because sending data from the main thread to workers and backwards would increase the latency.
import { getLocalstorageMetaOptimizerRxStorage } from 'rxdb-premium/plugins/storage-localstorage-meta-optimizer';
import { getMemorySyncedRxStorage } from 'rxdb-premium/plugins/storage-memory-synced';
import { getRxStorageOPFSMainThread } from 'rxdb-premium/plugins/storage-worker';
const myDatabase = await createRxDatabase({
storage: getLocalstorageMetaOptimizerRxStorage({
storage: getMemorySyncedRxStorage({
storage: getRxStorageOPFSMainThread()
})
})
});