RxDB 17 im Heimlab: Serverless Daten verstehen & nutzen
RxDB 17: Die Revolution der lokalen Datenhaltung im Heimlab
Servus, liebe Heimlab-Enthusiasten und Admins!
Wer mich kennt, weiß, dass ich ein großer Fan davon bin, Systeme zu vereinfachen und Abhängigkeiten zu reduzieren, wo immer es geht. In meiner Erfahrung im Home Lab stoße ich immer wieder auf Projekte, die eine kleine Datenbank benötigen, aber gleich einen ganzen Server (oder Container) für PostgreSQL, MongoDB oder ähnliches mitbringen. Das ist oft Overkill und erhöht die Komplexität. Genau hier kommt RxDB ins Spiel – und mit Version 17 wird es noch spannender.
Die Heise-Meldung über RxDB 17 und seinen "Sync ohne Server" über Google Drive oder OneDrive hat bei mir sofort die Alarmglocken läuten lassen. Das ist nicht nur für App-Entwickler relevant, sondern auch für uns, die wir im Heimlab gerne mal ein kleines Dashboard basteln, Sensordaten lokal vorhalten oder kleine Tools entwickeln, die ohne eine riesige Infrastruktur auskommen sollen. Stell dir vor, du hast eine kleine Web-App, die deine Smart-Home-Inventarliste verwaltet, und diese Daten synchronisieren sich einfach im Hintergrund mit deinem Google Drive – ohne dass du einen eigenen Datenbankserver betreiben musst. Das ist genial!
In diesem Praxis-Guide werden wir uns RxDB 17 genauer ansehen. Wichtig: Der Heise-Artikel beschreibt eine Funktion, die primär für Entwickler gedacht ist, die RxDB in ihren Anwendungen nutzen. Ich werde dir hier keine fertige "One-Click-Lösung" für eine Cloud-Sync-Integration präsentieren, denn das erfordert immer noch das Schreiben von Code und die Interaktion mit Cloud-APIs. Stattdessen legen wir das Fundament: Wir richten eine RxDB-Instanz ein, lernen, wie man damit lokal arbeitet und verstehen das Konzept des "Local-First" und der reaktiven Datenhaltung. So bist du bestens gerüstet, um die neuen Serverless-Sync-Möglichkeiten in deinen eigenen kleinen Heimlab-Projekten zu experimentieren.
Was ist RxDB und warum ist es für uns interessant?
RxDB ist eine reaktive, offline-fähige und NoSQL-Datenbank für JavaScript-Anwendungen. "Reaktiv" bedeutet, dass deine Anwendung automatisch auf Datenänderungen reagiert. Stell dir vor, du aktualisierst einen Wert in der Datenbank, und dein Dashboard-Widget, das diesen Wert anzeigt, aktualisiert sich sofort, ohne dass du es explizit neu laden musst. Das ist mächtig!
Warum ist das für uns im Heimlab interessant?
- Offline-First: Deine Anwendung funktioniert auch, wenn das Netzwerk mal spinnt oder du keinen Internetzugang hast. Alle Daten werden lokal gespeichert und bei Bedarf synchronisiert. Perfekt für kleine Tools, die auf einem Raspberry Pi laufen und nicht immer Online sein müssen.
- Performance: Da die Daten lokal im Browser (oder auf dem Server/Node.js-Prozess) gespeichert werden, sind Abfragen blitzschnell.
- Flexibilität (NoSQL): Du bist nicht an starre Schemas gebunden, was bei experimentellen Projekten im Heimlab sehr praktisch sein kann. Dennoch kannst du Schemas definieren, um Datenkonsistenz zu gewährleisten.
- Einfache Synchronisation: Hier kommt RxDB 17 ins Spiel. Die Möglichkeit, Daten direkt mit Cloud-Speichern wie Google Drive oder OneDrive zu synchronisieren, ohne ein eigenes Backend aufsetzen zu müssen, ist ein echter Game Changer für kleinere Projekte. Kein eigener Sync-Server, keine komplexen APIs – einfach die RxDB-Sync-Adapter nutzen.
Der Clou von Version 17 ist genau diese serverlose Synchronisation. Statt einen eigenen Server zu betreiben, der die Daten zwischen verschiedenen Clients synchronisiert, nutzt RxDB nun Adapter, die direkt mit den APIs von Google Drive oder OneDrive sprechen. Das bedeutet, dass die Cloud-Speicher als "Single Source of Truth" dienen und RxDB sich um die Konfliktauflösung und das Merging der Daten kümmert. Das reduziert die Komplexität deines Setups erheblich und ist ideal für kleine, verteilte Anwendungen oder Tools, die du vielleicht auf verschiedenen Geräten nutzen möchtest.
Voraussetzungen
Bevor wir loslegen, stellen wir sicher, dass dein System bereit ist. Die meisten meiner Heimlab-Systeme laufen auf Debian-basierten Distributionen (Proxmox-Container, Raspberry Pis), daher gehe ich davon aus, dass du ähnliche Umgebungen nutzt.
- Grundlegende Linux-Kenntnisse: Du solltest dich auf der Kommandozeile wohlfühlen und wissen, wie man Pakete installiert.
- Node.js und npm: RxDB ist eine JavaScript-Bibliothek, die Node.js als Laufzeitumgebung benötigt. Ich empfehle, `nvm` (Node Version Manager) zu verwenden, um verschiedene Node.js-Versionen einfach zu verwalten. So gerätst du nicht in Abhängigkeitskonflikte.
# nvm installieren (falls noch nicht geschehen)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
source ~/.bashrc # Oder ~/.zshrc, je nach Shell
# Neueste LTS-Version von Node.js installieren und nutzen
nvm install --lts
nvm use --lts
# Prüfen, ob Node.js und npm installiert sind
node -v
npm -v
Schritt-für-Schritt: Dein erstes RxDB-Projekt im Heimlab
Jetzt wird's praktisch! Wir erstellen ein kleines Node.js-Projekt, das RxDB verwendet, um einige simulierte "Heimlab-Sensorwerte" zu speichern und abzurufen. Das ist ein perfektes Szenario, um die lokalen Fähigkeiten von RxDB zu demonstrieren.
1. Projektinitialisierung
Zuerst erstellen wir ein neues Verzeichnis für unser Projekt und initialisieren es mit `npm`.
# Ein neues Verzeichnis erstellen und wechseln
mkdir my-rxdb-lab-status
cd my-rxdb-lab-status
# Ein neues Node.js-Projekt initialisieren
npm init -y
# RxDB und den PouchDB-IDB-Adapter installieren
# PouchDB-IDB-Adapter ist für die Speicherung im Browser (IndexedDB) oder in Node.js (LevelDB/SQLite via PouchDB)
npm install rxdb pouchdb-adapter-idb
Mein Tipp: `pouchdb-adapter-idb` ist gut für den Start. Für serverseitige Node.js-Anwendungen oder Docker-Container, in denen du persistente Speicherung auf dem Dateisystem haben möchtest, könntest du auch `pouchdb-adapter-leveldb` oder `pouchdb-adapter-sqlite` in Betracht ziehen. Für dieses erste Experiment reicht `idb` oder der Standard-Memory-Adapter.
2. Die Datenbank einrichten und Schema definieren
Jetzt erstellen wir unsere Hauptdatei, nennen wir sie `index.js`, und richten darin unsere RxDB-Datenbank ein. Wir definieren ein einfaches Schema für unsere "LabStatus"-Messwerte (z.B. Temperatur, Luftfeuchtigkeit).
Erstelle die Datei `index.js` im Projektverzeichnis:
// index.js
const { createRxDatabase } = require('rxdb');
const { getRxStoragePouch } = require('rxdb/plugins/pouchdb');
const { addRxPlugin } = require('rxdb');
const { RxDBReplicationGraphQLPlugin } = require('rxdb/plugins/replication-graphql'); // Beispiel für einen Plugin-Import, falls man ihn nutzen würde
const { RxDBJsonDumpPlugin } = require('rxdb/plugins/json-dump'); // Für Export/Import
const { RxDBQueryBuilderPlugin } = require('rxdb/plugins/query-builder'); // Für erweiterte Queries
// Wichtige Plugins hinzufügen
addRxPlugin(RxDBJsonDumpPlugin);
addRxPlugin(RxDBQueryBuilderPlugin);
// addRxPlugin(RxDBReplicationGraphQLPlugin); // Nur falls du GraphQL-Replikation nutzen möchtest
// Unser Schema für die LabStatus-Messwerte
const labStatusSchema = {
version: 0,
primaryKey: 'id',
type: 'object',
properties: {
id: {
type: 'string',
maxLength: 100 // Wichtig für primaryKey
},
sensorId: {
type: 'string',
maxLength: 100
},
temperature: {
type: 'number'
},
humidity: {
type: 'number'
},
timestamp: {
type: 'number' // Unix-Timestamp
}
},
required: ['id', 'sensorId', 'temperature', 'humidity', 'timestamp']
};
const setupDatabase = async () => {
console.log('Starte RxDB-Setup...');
// Datenbank instanziieren
const db = await createRxDatabase({
name: 'homelabstatusdb', // Name der Datenbank
storage: getRxStoragePouch('idb') // Verwende den PouchDB-IDB-Adapter
// password: 'meinSuperSicheresPasswort' // Optional: Verschlüsselung aktivieren
});
console.log('Datenbank erstellt:', db.name);
// Eine Collection hinzufügen (entspricht einer Tabelle in relationalen DBs)
await db.addCollections({
labstatus: {
schema: labStatusSchema
}
});
console.log('Collection "labstatus" hinzugefügt.');
return db;
};
// Datenbank-Setup aufrufen und exportieren
module.exports = setupDatabase;
Wichtig zu wissen: Das `version: 0` im Schema ist der Anfang. Wenn du später Änderungen am Schema vornimmst (z.B. neue Felder hinzufügst), musst du die Version erhöhen und Migrationsfunktionen bereitstellen. Das ist ein fortgeschrittenes Thema, aber gut zu wissen für die Zukunft.
3. Daten hinzufügen und abfragen
Jetzt, wo unsere Datenbank und Collection bereit sind, können wir Daten einfügen und abfragen. Wir erweitern `index.js` oder erstellen eine neue Datei, um die Datenbank zu nutzen.
Um es einfach zu halten, erweitern wir die `index.js` um eine `run` Funktion, die Daten einfügt und abfragt:
// index.js (Erweiterung)
// ... (vorheriger Code für setupDatabase und labStatusSchema) ...
const run = async () => {
const db = await setupDatabase();
const labStatusCollection = db.labstatus;
console.log('\nFüge neue LabStatus-Daten hinzu...');
const now = Date.now();
await labStatusCollection.insert({
id: `sensor_temp_01_${now}`,
sensorId: 'temp_sensor_01',
temperature: 22.5 + Math.random() * 2,
humidity: 60.1 + Math.random() * 5,
timestamp: now
});
await labStatusCollection.insert({
id: `sensor_hum_02_${now + 1}`,
sensorId: 'hum_sensor_02',
temperature: 21.0 + Math.random() * 1,
humidity: 65.5 + Math.random() * 3,
timestamp: now + 1
});
console.log('Daten erfolgreich hinzugefügt.');
console.log('\nFrage alle LabStatus-Daten ab...');
const allReadings = await labStatusCollection.find().exec();
console.log('Alle Messwerte:', allReadings.map(doc => doc.toJSON()));
console.log('\nFrage reaktiv nach Temperaturänderungen ab...');
// Hier demonstrieren wir die Reaktivität von RxDB
// Diese Subscription bleibt aktiv und reagiert auf Änderungen
const subscription = labStatusCollection.find({
selector: {
temperature: { $gt: 22 } // Alle Messwerte mit Temperatur über 22
}
}).$.subscribe(docs => {
console.log('Reaktive Abfrage: Änderungen für Temperaturen > 22:', docs.map(doc => doc.toJSON()));
});
// Füge nach kurzer Zeit weitere Daten hinzu, um die Reaktivität zu demonstrieren
setTimeout(async () => {
console.log('\nFüge nach 3 Sekunden weitere Daten hinzu...');
const newNow = Date.now();
await labStatusCollection.insert({
id: `sensor_temp_03_${newNow}`,
sensorId: 'temp_sensor_01',
temperature: 23.8 + Math.random() * 1, // Dieser sollte die Subscription triggern
humidity: 61.2 + Math.random() * 2,
timestamp: newNow
});
}, 3000);
// Warte kurz, damit die Reaktivität demonstriert werden kann
// In einer echten Anwendung würdest du das nicht so machen, sondern z.B. einen Webserver starten
await new Promise(resolve => setTimeout(resolve, 5000));
subscription.unsubscribe(); // Subscription wieder aufräumen
console.log('\nRxDB-Demonstration abgeschlossen.');
// Datenbank schließen
await db.destroy();
console.log('Datenbank geschlossen.');
};
run().catch(err => console.error('Fehler im RxDB-Projekt:', err));
Um das Skript auszuführen, speichere die Änderungen in `index.js` und führe es im Terminal aus:
node index.js
Du solltest sehen, wie die Datenbank initialisiert wird, Daten eingefügt werden, alle Daten abgefragt werden und dann nach 3 Sekunden eine weitere Insertion die reaktive Abfrage triggert. Das ist das Herzstück von RxDB!
4. Der Serverless Sync Gedanke
Die Magie von RxDB 17 liegt in den neuen Serverless-Sync-Adaptern. Der Heise-Artikel erwähnt Google Drive und OneDrive. Im Kern bedeutet das, dass du deine RxDB-Datenbank nicht nur lokal speicherst, sondern sie auch mit einem dieser Cloud-Dienste synchronisieren kannst, ohne einen eigenen Backend-Server betreiben zu müssen. Die Cloud wird zur zentralen "Quelle der Wahrheit".
Wie funktioniert das prinzipiell?
RxDB bietet spezielle Replikations-Plugins. Für Google Drive und OneDrive gibt es nun Adapter, die die jeweilige Cloud-API nutzen. Du würdest in deiner Anwendung (z.B. in der `index.js` oder einer Web-App) den entsprechenden Adapter konfigurieren, deine Cloud-Zugangsdaten (oder ein OAuth-Token) bereitstellen und RxDB würde dann im Hintergrund die Synchronisation übernehmen.
Ein vereinfachtes, konzeptionelles Beispiel, wie der Aufruf aussehen könnte (dieser Code ist *nicht* lauffähig, da er die genaue Implementierung des Adapters und der Authentifizierung voraussetzt, die im Heise-Artikel nicht detailliert ist und komplexer ist):
// Konzeptionelles Beispiel für Serverless Sync (NICHT DIREKT LAUFFÄHIG)
// Annahme: Ein Google Drive Sync Plugin existiert und ist installiert
// const { RxDBGoogleDriveReplicationPlugin } = require('rxdb/plugins/replication-google-drive');
// addRxPlugin(RxDBGoogleDriveReplicationPlugin);
// ... innerhalb deiner run-Funktion, nachdem die Collection erstellt wurde ...
// const startGoogleDriveSync = async (collection) => {
// console.log('Starte Google Drive Synchronisation...');
// const replicationState = await collection.syncGoogleDrive({
// clientId: 'DEINE_GOOGLE_CLIENT_ID',
// redirectUri: 'DEINE_REDIRECT_URI',
// folderName: 'RxDB_Homelab_Sync', // Ordner in Google Drive
// pull: {}, // Optionen für den Pull-Vorgang
// push: {}, // Optionen für den Push-Vorgang
// live: true, // Kontinuierliche Synchronisation
// autoStart: true,
// // ... weitere Optionen für Authentifizierung und Konfliktauflösung
// });
// replicationState.error$.subscribe(err => {
// console.error('Google Drive Sync Fehler:', err);
// });
// replicationState.change$.subscribe(change => {
// console.log('Google Drive Sync Änderung:', change);
// });
// console.log('Google Drive Synchronisation gestartet.');
// return replicationState;
// };
// // Beispielaufruf:
// // const googleDriveSync = await startGoogleDriveSync(labStatusCollection);
// // ... dann könntest du googleDriveSync.cancel() aufrufen, um die Sync zu beenden.
Wie du siehst, erfordert das die Integration von API-Schlüsseln und Authentifizierungsflüssen, die über einen einfachen "Installations-Guide" hinausgehen und tief in die Anwendungsentwicklung reichen. Mein Tipp ist, zuerst die lokalen RxDB-Konzepte zu meistern und dann die offizielle RxDB-Dokumentation für die spezifischen Sync-Adapter und deren Konfiguration zu konsultieren, sobald du bereit bist, eine echte Anwendung zu bauen.
Integration in dein Heimlab: Ideen und Möglichkeiten
Jetzt, da du ein Gefühl für RxDB hast, lass uns überlegen, wie du das in deinem Heimlab nutzen könntest:
- Custom Dashboards für Home Assistant: Stell dir vor, du baust ein kleines, eigenständiges Web-Dashboard für spezifische Daten, die Home Assistant nicht optimal darstellt. RxDB könnte diese Daten lokal cachen, reaktiv anzeigen und bei Bedarf mit einem Cloud-Dienst synchronisieren, falls du das Dashboard auch von unterwegs nutzen möchtest und eine zentrale Quelle brauchst.
- Offline-fähige Inventar- oder Projektmanagement-Tools: Du könntest eine kleine Web-App entwickeln, um dein Heimlab-Inventar (Server, VMs, Kabel) zu verwalten oder kleine Projekte zu tracken. RxDB sorgt dafür, dass du auch ohne Netzwerkverbindung arbeiten kannst.
- N8N und RxDB: N8N ist super für Automatisierungen. Du könntest N8N nutzen, um Daten von externen Quellen zu sammeln (APIs, MQTT, Webhooks) und diese dann über eine kleine, selbstgeschriebene API in deine RxDB-Instanz zu schreiben. Oder umgekehrt: N8N triggert Aktionen basierend auf Änderungen in deiner RxDB (wenn du eine kleine API davor hast, die RxDB überwacht).
- Docker-Container: Jede Node.js-Anwendung lässt sich wunderbar in einem Docker-Container verpacken. Deine RxDB-Anwendung könnte in einem Container laufen und ihre Daten entweder im Container-Dateisystem (gemounteter Volume für Persistenz) oder eben über die Cloud-Sync-Adapter persistieren. Das ist mein bevorzugter Weg, um neue Tools im Heimlab zu isolieren und zu verwalten.
Häufige Fehler und Lösungen
Beim Einstieg in neue Technologien stolpert man immer wieder über dieselben Hürden. Hier sind ein paar, die mir bei RxDB oder ähnlichen Node.js-Projekten begegnet sind:
- Falscher Pouch