JavaScripting

The definitive source of the best
JavaScript libraries, frameworks, and plugins.


  • ×

    Rxdb

    :computer: :iphone: A reactive Database for Progressive Web Apps and more
    Filed under 

    • 🔾84%Overall
    • 14,514
    • 7 hours
    • 🕩654
    • 👥8
    Announcement
                 Version 9.0.0 is now released, read the ANNOUNCEMENT               

    RxDB

    A realtime Database for JavaScript Applications

    RxDB (short for Reactive Database) is a NoSQL-database for JavaScript Applications like Websites, hybrid Apps, Electron-Apps, Progressive Web Apps and NodeJs. Reactive means that you can not only query the current state, but subscribe to all state changes like the result of a query or even a single field of a document. This is great for UI-based realtime applications in way that makes it easy to develop and also has great performance benefits. To replicate data between your clients and server, RxDB provides modules for realtime replication with any CouchDB compliant endpoint and also with custom GraphQL endpoints.

    follow on Twitter


    reactive.gif


    Features
    💻📱 Multiplatform support for browsers, nodejs, electron, cordova, react-native and every other javascript-runtime
    📨 Reactive data-handling based on RxJS
    🚣 Offline first let your app still work when the users has no internet
    🔄 Replication between client and server-data, compatible with pouchdbPouchDB, couchdbCouchDB and cloudantIBM Cloudant. There is also a plugin for a GraphQL replication
    📄 Schema-based with the easy-to-learn standard of json-schema
    🍊 Mango-Query exactly like you know from mongoDB and mongoose
    🔐 Encryption of single data-fields to protect your users data
    📤📥 Import/Export of the database-state (json), awesome for coding with TDD
    📡 Multi-Window to synchronise data between different browser-windows or nodejs-processes
    💅 ORM-capabilities to easily handle data-code-relations and customize functions of documents and collections
    🔷 Full TypeScript support for fast and secure coding (Requires Typescript v3.8 or higher)

    Platform-support

    RxDB is made so that you can use exactly the same code at

    We optimized, double-checked and made boilerplates so you can directly start to use RxDB with frameworks like

    Quickstart

    Installation:

    npm install rxdb --save
    
    # peerDependencies
    npm install rxjs --save
    

    Import:

    import { createRxDatabase } from 'rxdb';
    const db = await createRxDatabase({
        name: 'heroesdb',
        adapter: 'indexeddb',
        password: 'myLongAndStupidPassword' // optional
      });                                                       // create database
    
    await db.collection({name: 'heroes', schema: mySchema});    // create collection
    db.heroes.insert({ name: 'Bob' });                          // insert document
    

    Feature-Showroom (click to toggle)

    Mango-Query

    To find data in your collection, use the mquery api to create chained mango-queries, which you maybe know from mongoDB or mongoose.

    javascript myCollection .find() .where('name').ne('Alice') .where('age').gt(18).lt(67) .limit(10) .sort('-age') .exec().then( docs => { console.dir(docs); });
    Reactive

    RxDB implements rxjs to make your data reactive. This makes it easy to always show the real-time database-state in the dom without manually re-submitting your queries.

    javascript db.heroes .find() .sort('name') .$ // <- returns observable of query .subscribe( docs => { myDomElement.innerHTML = docs .map(doc => '<li>' + doc.name + '</li>') .join(); }); reactive.gif
    MultiWindow/Tab

    When two instances of RxDB use the same storage-engine, their state and action-stream will be broadcasted. This means with two browser-windows the change of window #1 will automatically affect window #2. This works completely offline.

    multiwindow.gif
    Replication

    Because RxDB relies on glorious PouchDB, it is easy to replicate the data between devices and servers. And yes, the changeEvents are also synced.

    sync.gif
    Schema

    Schemas are defined via jsonschema and are used to describe your data.

    javascript const mySchema = { title: "hero schema", version: 0, // <- incremental version-number description: "describes a simple hero", type: "object", properties: { name: { type: "string", primary: true // <- this means: unique, required, string and will be used as '_id' }, secret: { type: "string", }, skills: { type: "array", maxItems: 5, uniqueItems: true, item: { type: "object", properties: { name: { type: "string" }, damage: { type: "number" } } } } }, required: ["color"], encrypted: ["secret"] // <- this means that the value of this field is stored encrypted };
    Encryption

    By setting a schema-field to encrypted, the value of this field will be stored in encryption-mode and can't be read without the password. Of course you can also encrypt nested objects. Example:

    json { "title": "my schema", "properties": { "secret": { "type": "string", "encrypted": true } }, "encrypted": [ "secret" ] }
    Level-adapters

    The underlying pouchdb can use different adapters as storage engine. So you can use RxDB in different environments by just switching the adapter. For example you can use websql in the browser, localstorage in mobile-browsers and a leveldown-adapter in nodejs.

    js // this requires the indexeddb-adapter RxDB.plugin(require('pouchdb-adapter-idb')); // this creates a database with the indexeddb-adapter const database = await RxDB.create({ name: 'mydatabase', adapter: 'indexeddb' // the name of your adapter }); There is a big ecosystem of adapters you can use.
    Import / Export

    RxDB lets you import and export the whole database or single collections into json-objects. This is helpful to trace bugs in your application or to move to a given state in your tests.

    js // export a single collection const jsonCol = await myCollection.dump(); // export the whole database const jsonDB = await myDatabase.dump(); // import the dump to the collection await emptyCollection.importDump(json); // import the dump to the database await emptyDatabase.importDump(json);
    Leader-Election

    Imagine your website needs to get a piece of data from the server once every minute. To accomplish this task you create a websocket or pull-interval. If your user now opens the site in 5 tabs parallel, it will run the interval or create the socket 5 times. This is a waste of resources which can be solved by RxDB's LeaderElection.

    js myRxDatabase.waitForLeadership() .then(() => { // this will only run when the instance becomes leader. mySocket = createWebSocket(); }); In this example the leader is marked with the crown ♛ reactive.gif
    Key-Compression

    Depending on which adapter and in which environment you use RxDB, client-side storage is limited in some way or the other. To save disc-space, RxDB uses a schema based keycompression to minimize the size of saved documents. This saves about 40% of used storage.

    Example: js // when you save an object with big keys await myCollection.insert({ firstName: 'foo' lastName: 'bar' stupidLongKey: 5 }); // key compression will internally transform it to { '|a': 'foo' '|b': 'bar' '|c': 5 } // so instead of 46 chars, the compressed-version has only 28 // the compression works internally, so you can of course still access values via the original key.names and run normal queries. console.log(myDoc.firstName); // 'foo'
    EventReduce

    One big benefit of having a realtime database is that big performance optimizations can be done when the database knows a query is observed and the updated results are needed continuously. RxDB internally uses the Event-Reduce algorithm. This makes sure that when you update/insert/remove documents, the query does not have to re-run over the whole database but the new results will be calculated from the events. This creates a huge performance-gain with zero cost.

    ### Use-Case-Example Imagine you have a very big collection with many user-documents. At your page you want to display a toplist with users which have the most points and are currently logged in. You create a query and subscribe to it. js const query = usersCollection.find().where('loggedIn').eq(true).sort('points'); query.$.subscribe(users => { document.querySelector('body').innerHTML = users .reduce((prev, cur) => prev + cur.username+ '<br/>', ''); }); As you may detect, the query can take very long time to run, because you have thousands of users in the collection. When a user now logs off, the whole query will re-run over the database which takes again very long. js anyUser.loggedIn = false; await anyUser.save(); But not with the EventReduce. Now, when one user logs off, it will calculate the new results from the current results plus the RxChangeEvent. This often can be done in-memory without making IO-requests to the storage-engine. EventReduce not only works on subscribed queries, but also when you do multiple .exec()'s on the same query.

    Getting started

    Get started now by reading the docs or exploring the example-projects.

    Contribute

    Check out how you can contribute to this project.

    Follow up

    • Follow RxDB on twitter to not miss the latest enhancements.
    • Join the chat on gitter for discussion.

    Thank you

    A big Thank you to every contributor of this project.

    License

    Apache-2.0

    Show All