2. Wer bin ich
Dipl. Inf. (FH) Oliver Kurowski
Studium Medieninformatik an der TFH-Berlin (Beuth Hochschule für Technik)
Abschluss 2003 (Dipl.)
Erster Computer: Apple II 1983
Seit 2003: KW automotive GmbH
Div. Fachartikel im PHP-Magazin
2012: Buch „CouchDB mit PHP“
(www.CouchDBmitPHP.de)
Twitter: @okurow
Mail: oliver@thinkcouchdb.com
Oliver Kurowski, @okurow
4. Was ist CouchDB?
Eine NoSQL Datenbank
die Ihre Dokumente in JSON speichert,
JavaScript für MapReduce benutzt,
über HTTP angesprochen wird,
Multi-Master-Replikationen ermöglicht,
mit Attachments an Datendokumenten eigene Programme innerhalb der
CouchDB erlaubt,
Und in Erlang geschrieben ist.
2005 Anfang der Entwicklung von Damien Katz, ehemaliger Lotus Notes
Entwickler. Seit 2008 hauptberuflich.
Nov 2008: Apache Project
2012: Mit Couchbase ein neues kommerzielles Produkt
Oliver Kurowski, @okurow
5. Wo läuft CouchDB?
Windows (binaries auf couchdb.apache.org)
Lunux (Sourcecode auf der Hompage, diverse build-tools erhältlich)
Mac OSX
Zum Testen: iriscouch.com / cloudant.com
Oliver Kurowski, @okurow
6. Übersicht der Funktionen
Spricht HTTP
Schemalose Dokumente im JSON-Format
MVCC Multiversion Concurrency Control
MapReduce zum Indizieren und Abfragen der Daten
Transformationsfunktionen zum Anpassen der Ausgabe
Replikationen mit Filtermöglichkeit
Automatische/manuelle Funktionen beim Speichern von Dokumenten
Binäre Attachments für Dokumente
Integrierte HTML-Oberfläche Futon
Oliver Kurowski, @okurow
7. Vokabular
CouchDB : Eine CouchDB installation
Datenbank: Eine Datenbank innerhalb einer CouchDB
Dokument: Ein Datensatz innerhalb einer Datenbank
Oliver Kurowski, @okurow
8. Dokumente in CouchDB
Schemalos
JSON
{
“_id“: “1“,
“_rev“: “1-axcv“,
“doctype“: “fahrzeug“,
“hersteller“: “Audi“,
“modell“: “A3“,
“baujahr“: 2000,
“extras“: [“Alufelgen“,“Klimaanlage“]
}
Keine Gruppierung von Dokumenten, daher Feld “doctype“
Oliver Kurowski, @okurow
9. Kommunikation über HTTP
REST API:
GET ruft Daten ab
PUT/POST sendet Daten
DELETE löscht einen Datensatz
COPY kopiert einen Datensatz
Auf der Kommandozeile mit curl:
$ curl –X PUT http://localhost:5984/fahrzeuge
{“ok“:true}
$ curl –X PUT http://localhost:5984/fahrzeuge/1
-d ‘{“doctype“:“fahrzeug“, “hersteller“:“Audi“, “modell“:“A3“}‘
{“ok“:true, “id“:“1“, “rev“:“1-a4b7a34..“}
$ curl –X GET http://localhost:5984/fahrzeuge/1
{“_id“:“1“, “_rev“: “1-a4b7a34..“, “doctype“: “fahrzeug“, “hersteller“: “Audi“,“modell“: “A3“}
$ curl –X GET http://localhost:5984/fahrzeuge/2
{“error“:“not found“, “reason“:“missing“}
Oliver Kurowski, @okurow
11. MVCC – Multiversion Concurrency Control
MVCC ermöglicht nichtblockierendes Schreiben auf eine Datenbank.
Die neue Version eines Dokuments wird an die alte Version angehangen.
Dabei erhöht sich die Revisionsnummer des Dokuments.
Oliver Kurowski, @okurow
12. MVCC – Multiversion Concurrency Control
MVCC ermöglicht nichtblockierendes Schreiben auf eine Datenbank.
Die neue Version eines Dokuments wird an die alte Version angehangen.
Dabei erhöht sich die Revisionsnummer des Dokuments.
Oliver Kurowski, @okurow
13. MVCC – Multiversion Concurrency Control
MVCC ermöglicht nichtblockierendes Schreiben auf eine Datenbank.
Die neue Version eines Dokuments wird an die alte Version angehangen.
Dabei erhöht sich die Revisionsnummer des Dokuments.
Oliver Kurowski, @okurow
14. MVCC – Multiversion Concurrency Control
MVCC ermöglicht nichtblockierendes Schreiben auf eine Datenbank.
Die neue Version eines Dokuments wird an die alte Version angehangen.
Dabei erhöht sich die Revisionsnummer des Dokuments.
Oliver Kurowski, @okurow
15. MVCC – Multiversion Concurrency Control
MVCC ermöglicht nichtblockierendes Schreiben auf eine Datenbank.
Die neue Version eines Dokuments wird an die alte Version angehangen.
Dabei erhöht sich die Revisionsnummer des Dokuments.
Oliver Kurowski, @okurow
16. MVCC – Multiversion Concurrency Control
Bei gleichzeitiger Bearbeitung eines Dokuments „gewinnt“ derjenige, der es
zuerst speichert. Dadurch erhöht sich die Revisionsnummer des Dokuments,
und der Langsamere hat damit eine überholte Revisionsnummer,
das Speichern wird abgelehnt
Oliver Kurowski, @okurow
17. MVCC – Multiversion Concurrency Control
Bei gleichzeitiger Bearbeitung eines Dokuments „gewinnt“ derjenige, der es
zuerst speichert. Dadurch erhöht sich die Revisionsnummer des Dokuments,
und der Langsamere hat damit eine überholte Revisionsnummer,
das Speichern wird abgelehnt
Oliver Kurowski, @okurow
18. MVCC – Multiversion Concurrency Control
Bei gleichzeitiger Bearbeitung eines Dokuments „gewinnt“ derjenige, der es
zuerst speichert. Dadurch erhöht sich die Revisionsnummer des Dokuments,
und der Langsamere hat damit eine überholte Revisionsnummer,
das Speichern wird abgelehnt
Oliver Kurowski, @okurow
19. MVCC – Multiversion Concurrency Control
Bei gleichzeitiger Bearbeitung eines Dokuments „gewinnt“ derjenige, der es
zuerst speichert. Dadurch erhöht sich die Revisionsnummer des Dokuments,
und der Langsamere hat damit eine überholte Revisionsnummer,
das Speichern wird abgelehnt
Oliver Kurowski, @okurow
20. MVCC – Multiversion Concurrency Control
Bei gleichzeitiger Bearbeitung eines Dokuments „gewinnt“ derjenige, der es
zuerst speichert. Dadurch erhöht sich die Revisionsnummer des Dokuments,
und der Langsamere hat damit eine überholte Revisionsnummer,
das Speichern wird abgelehnt
Oliver Kurowski, @okurow
21. MVCC – Multiversion Concurrency Control
Bei gleichzeitiger Bearbeitung eines Dokuments „gewinnt“ derjenige, der es
zuerst speichert. Dadurch erhöht sich die Revisionsnummer des Dokuments,
und der Langsamere hat damit eine überholte Revisionsnummer,
das Speichern wird abgelehnt
Oliver Kurowski, @okurow
22. MVCC – Multiversion Concurrency Control
Bei gleichzeitiger Bearbeitung eines Dokuments „gewinnt“ derjenige, der es
zuerst speichert. Dadurch erhöht sich die Revisionsnummer des Dokuments,
und der Langsamere hat damit eine überholte Revisionsnummer,
das Speichern wird abgelehnt
Oliver Kurowski, @okurow
23. MVCC – Multiversion Concurrency Control
Bei gleichzeitiger Bearbeitung eines Dokuments „gewinnt“ derjenige, der es
zuerst speichert. Dadurch erhöht sich die Revisionsnummer des Dokuments,
und der Langsamere hat damit eine überholte Revisionsnummer,
das Speichern wird abgelehnt
Oliver Kurowski, @okurow
24. MVCC – Multiversion Concurrency Control
Die Revisionsnummer eines Dokuments wird von der CouchDB gesetzt.
Jede Änderung eines Dokuments muss mit der aktuellen Revisionsnummer
angegeben werden.
$ curl –X PUT http://localhost:5984/fahrzeuge/1
-d ‘{“doctype“:“fahrzeug“, “hersteller“:“Audi“, “modell“:“A3“, “baujahr“:2000,
“_rev“:“1-a4b7a34..“}‘
{“ok“:true, “id“:“1“, “rev“:“2-7c45a..“}
$ curl –X PUT http://localhost:5984/fahrzeuge/1
-d ‘{“doctype“:“fahrzeug“, “hersteller“:“Audi“, “modell“:“A3“, “baujahr“:2000“}‘
{“error“:“conflict“, “reason“:“Document update conflict“}
$ curl –X DELETE http://localhost:5984/fahrzeuge/1?rev=2-7c45a..
{“ok“:true, “id“:“1“, “rev“:“3-e94x..“}
$ curl –X GET http://localhost:5984/fahrzeuge/1
{“error“:“not found“, “reason“:“deleted“}
Oliver Kurowski, @okurow
26. Views
Eine View ist ein Container für eine Map- und optional Reduce Funktion.
Standardmäßig sind die Funktionen in JavaScript geschrieben,
andere Sprachen können aber eingestellt werden.
Views können Daten
Filtern
Gruppieren
Auswerten
Oliver Kurowski, @okurow
27. Views
Views werden innerhalb spezieller Dokumente (Designdokumente) in einer
Datenbank gespeichert, und wie Datendokemente abgerufen:
{
“_id“: “_design/abfragen“,
“_rev“: “1-e7fg“,
“views“: {
“nachHersteller“: {
“map“:“function(doc) {…}“,
“reduce“:“function(keys,values) {…}“
}
}
}
Bsp:
http://localhost:5984/fahrzeugDatenbank/_design/abfragen/_view/nachHersteller
Oliver Kurowski, @okurow
28. Die Map-Funktion
Hat ein einzelnes Dokument als Input
Kann Key/Value Paare ausgeben. Dabei können die Werte aus allen JSON-Typen
bestehen:
- Spezialwerte: null, true, false
- Zahlen: 1e-17, 1.5, 200
- Strings : “+“, “1“, “Ab“, “Audi“
- Arrays: [1], [1,2], [1,“Audi“,true]
- Objekte: {“price“:1300,“sold“:true}
Die Ausgegebenen Key/Value Paare aller Dokumente werden in einer Liste
gespeichert,die nach den Werten der Keys aufsteigend sortiert ist.
Zusätzlich zu jedem Key/Value paar wird auch die Dokument-ID ausgegeben
Oliver Kurowski, @okurow
29. Die Map-Funktion Beispiel
Datendokumente:
Id: 1 Id: 2 Id: 3 Id: 4 Id: 5
hersteller: Audi hersteller : Audi hersteller : VW hersteller : VW hersteller : VW
modell: A3 modell: A4 modell: Golf modell: Golf modell: Polo
baujahr: 2000 baujahr : 2009 baujahr : 2009 baujahr : 2008 baujahr : 2010
preis: 5.400 preis: 16.000 preis: 15.000 preis: 9.000 preis: 12.000
Map-Funktion in JavaScript in einer View “nachPreis“:
„nachPreis“: {
“map“:“function(doc) {
emit (doc.preis, doc.hersteller+‘-‘+doc.modell+‘-‘+doc.baujahr);
}“
}
Ergebnis von _view/nachPreis:
{"total_rows":5,"offset":0,
"rows":[
{"id":"1","key":5.400,"value":“Audi-A3-2000“},
{"id":"2","key":9.000,"value":“VW-Golf-2008“},
{"id":"3","key":12.000,"value":“VW-Polo-2010“},
{"id":"4","key":15.000,"value":“VW-Golf-2009“},
{"id":"5","key":16.000,"value":“Audi-A4-2009“} ]}
Oliver Kurowski, @okurow
30. Die Map-Funktion steuern
Zur Abfragezeit kann die Ausgabe eine View beeinflusst werden:
_view/nachPreis?key=9.000
{"total_rows":5,"offset":1,
"rows":[
{"id":"2","key":9.000,"value":“VW-Golf-2008“},]}
_view/nachPreis?endkey=10.000
{"total_rows":5,"offset":0,
"rows":[
{"id":"1","key":5.400,"value":“Audi-A3-2000“},
{"id":"2","key":9.000,"value":“VW-Golf-2008“},]}
_view/nachPreis?startkey=10.000&endkey=15.500
{"total_rows":5,"offset":2,
"rows":[
{"id":"3","key":12.000,"value":“VW-Polo-2010“},
{"id":"4","key":15.000,"value":“VW-Golf-2009“} ]}
Oliver Kurowski, @okurow
31. Die Reduce-Funktion
Hat die Ergebnisse aus der Map-Phase als Input
Soll diese Liste auf einen einzelnen Wert reduzieren
Wird nach der Map-Phase automatisch ausgeführt
Oliver Kurowski, @okurow
32. Die Reduce-Funktion Beispiel
Erweiterung der View „nachPreis“
„nachPreis“: {
“map“:“function(doc) {
emit (doc.preis, doc.hersteller+‘-‘+doc.modell+‘-‘+doc.baujahr);
}“,
“reduce“:“function(keys,values) {
return (count(values) ); //_count
}“
}
}
Ergebnis von _view/nachPreis:
{"rows":[
{"key":null, "value":5 } ]}
_view/nachPreis?endkey=10.000
{"rows":[
{"key":null, "value":2 } ]}
Oliver Kurowski, @okurow
33. View Parameter
limit: Begrenzt die Anzahl der Ergebnisse
skip: Überspringt eine Anzahl von Egebnissen
include_docs=true: Ohne Reduce-Phase wird das entsprechende Dokument
zusätzlich zu jeder Zeile der Map-Liste ausgegeben
key, startkey,endkey: Bestimme Keys, bzw. Bereiche liefern
startkey_docid=x: Nur Dokumente mit der id>=x
endkey_docid=x: Nur Dokumente mit der id<x
descending=true: Umgekehrte Sortierreihenfolge (!)
stale=ok: Zeige die gespeicherten Werte, kein Aufruf der View
stale=update_after: Zeige die gespeicherten Werte, danach Aufruf der View
und Durchlauf MapReduce Phase
group, group_level,reduce=false: Gruppierungen der Keys, sofern Arrays
Oliver Kurowski, @okurow
36. Transformationsfunktionen
Dokumente sind JSON Objekte
Ergebnisse von Views sind ebenfalls JSON Objekte
CouchDB kann Serverseitig diese Daten formatiert liefern.
Shows: Transformationen für Datendokumente
Lists: Transformationen für Views
Shows und Lists werden zur Abfragezeit verarbeitet, d.h. bei großen
Datenmengen einen erheblichen Zeitaufwand.
Oliver Kurowski, @okurow
37. Shows: Dokumente transformieren
Datendokument (JSON): Show-Funktion in dem Designdokument:
{ “shows“: {
“Id“: “1“, “inHTML“:“function(doc,req) {
“hersteller“: “Audi“, var outS=‘‘;
“modell“: “A3“, outS=‘<b>‘+doc.hersteller+‘ ‘+doc.modell+‘</b><br>`;
“baujahr“: 2000, outS+=‘Baujahr: ‘+doc.baujahr+‘<br>‘;
“preis“: 5.400 outS+=‘Preis: ‘+doc.preis;
} return outS; }“
}
Ergebnis von _show/inHTML/1 :
Audi A3
Baujahr: 2000
Preis: 5.400
Oliver Kurowski, @okurow
38. List: Views transformieren
Ergebnis einer View nachPreis: List-Funktion in dem Designdokument:
{"total_rows":5,"offset":0, “lists“: {
"rows":[ “alsLI “:“function(head,req) {
{"id":"1","key":5.400,"value":“Audi-A3-2000“}, start({'code':200,'headers':{'Content-Type':'text/html'}});
{"id":"2","key":9.000,"value":“VW-Golf-2008“}, while(row=getRow()) {
{"id":"3","key":12.000,"value":“VW-Polo-2010“}, send(‘<li>‘+row.value+‘ :‘ +row.key+‘</li>‘);
{"id":"4","key":15.000,"value":“VW-Golf-2009“}, }
{"id":"5","key":16.000,"value":“Audi-A4-2009“} ]} }“
}
Ergebnis von _list/alsLi/nachPreis :
• Audi-A3-2000 : 5.400
• VW-Golf-2008 : 9.000
• VW-Polo-2010 : 12.000
• VW-Golf-2009 : 15.000
• Audi-A4-2009 : 16.000
Alle Steuerfunktionen einer View sind auch hier benutzbar
Oliver Kurowski, @okurow
39. Das Request Objekt
Shows und Lists haben Zugriff auf das Request Objekt mit folgenden Feldern:
(die Interessantesten)
Info: Informationen über die Datenbank
Id: übergebene Dokument ID (null, wenn keine übergeben wurde)
requested
_path: Der Aufruf in Einzelteilen, wie er gesendet wurde
headers: Vom Client gesendeter Header
userCTX: Informationen über den angemeldeten Benutzer
query: angehangene Parameter
Das Feld req.query erlaubt das Hinzufügen eigener Parameter an eine Abfrage
zum Steuern der Show/List.
Bsp: _show/inHTML/1?zeigePreis=true
Abfrage In der show-Funktion: if(req.query.zeigePreis==true) { ….}
Oliver Kurowski, @okurow
41. Funktionen beim Speichern
validate_doc_update
Automatische Validierung beim Speichern, kann Speichern verhindern
Funktionen werden automatisch aufgerufen
Pro Designdokument nur eine Funktion
Beim Speichern werden die Funktionen aller Designdokumente einer
Datenbank durchlaufen
Oliver Kurowski, @okurow
42. Funktionen beim Speichern
validate_doc_update Eingabgsparameter:
Das neues Dokument
eventuell vorhandenes Dokument mit der angegebenen ID
UserContext
function (newDoc,oldDoc,userCTX) {
if(!newDoc.name || newDoc.name==‘‘) {
throw ({ forbidden:‘Kein Name angegeben‘});
}
}
function (newDoc,oldDoc,userCTX) {
if(newDoc.name != oldDoc.name) {
throw ({ forbidden:‘Name darf nicht verändert werden‘});
}
}
function (newDoc,oldDoc,userCTX) {
if(userCTX.name !=‘oliver‘ ) {
throw ({ forbidden:‘Nur User oliver darf Daten schreiben‘});
}
}
Oliver Kurowski, @okurow
43. Funktionen beim Speichern
update
Datendokumente vor dem Speichern verändern, bzw. Speichern verhindern
expliziter Aufruf pro Speichervorgang
Mehrere Funktionen in einem Designdokument
Aber nur eine Funktion pro Speichervorgang auswählbar
Oliver Kurowski, @okurow
44. Funktionen beim Speichern
update Eingabgsparameter:
eventuell vorhandenes Dokument mit der angegebenen ID
request (mit neuen Daten im body-Feld)
Ermöglicht einfache Operationen auf Datendokumente, ohne die Dokumente
vorher zu laden:
Datendokument: update-Funktion:
{ function (doc,req) {
“_id“:“oliver“, if(doc!=null) {
“stimmen“:0 doc.stimmen+=1;
} return ({doc, ‘Anzahl der Stimmen:‘+doc.stimmen]);
}else{
return ({null,‘Person ‘+req.id+‘ nicht gefunden‘})
}
Aufruf:
$ curl –X PUT http://localhost:5984/personen/_design/operationen/update/pluseins/oliver
Anzahl Stimmen: 1
$ curl –X PUT http://localhost:5984/personen/_design/operationen/update/pluseins/oli
Person oli nicht gefunden
Oliver Kurowski, @okurow
46. Attachments
An bestehende Dokumente können Binärdaten angehangen werden
Große Dateien (Video, MP3) können ausschnittsweise geladen werden
Abrufen der Datei über die URL des Datendokuments:
http://localhost:5984/fahrzeuge/1/bild.jpg
http://localhost:5984/homepage/de/index.html
Das „/“ kann ein Teil des Dokumentnamens sein, dadurch Baumstruktur möglich
http://localhost:5984/homepage/de/bilder/1.jpg
Oliver Kurowski, @okurow
47. Attachments
Erzeugen einer neuen Datenbank und leeren Datensatzes:
$ curl -X PUT http://localhost:5984/websites
{“ok“:true}
$ curl -X PUT http://localhost:5984/websites/de -d‘{}‘
{"ok":true,"id":"de","rev":"1-967a00dff5e02add41819138abb3284d"}
Lokale Datei intex.html als Attachment speichern
$ curl -X PUT http://localhost:5984/websites/de/index.html?rev=1-
967a00dff5e02add41819138abb3284d -d @index.html -H “Content-type:text/html“
{"ok":true,"id":"de","rev":"2-f3f26739438d8f95570669c8fc886164"}
Aufruf im Browser:
http://localhost:5984/websites/de/index.html
Oliver Kurowski, @okurow
49. Replikation
Datenbank a Datenbank b
Master-Client
Oliver Kurowski, @okurow
50. Replikation
Datenbank a Datenbank b
Master-Master
Oliver Kurowski, @okurow
51. Replikation
Datenbank a Datenbank b
Datenbank c
Master-Master-Client
Oliver Kurowski, @okurow
52. Replikation
Datenbank a Datenbank b Datenbank f
Datenbank e Datenbank c Datenbank g
Multi-Master
Oliver Kurowski, @okurow
53. Replikation
Daten werden immer nur in eine Richtung Abgeglichen
pull: Datenbank holt sich die Daten
push: Datenbank schickt Daten
Bei Master-Master: 2 gegenseitige Replikationen
Es werden nur Änderungen von Dokumenten verglichen (_changes Feed),
d.h. wenn ein Dokument auf dem Client vorhanden ist, und auf dem Master
nicht, wird das Client-Dokument bei der Replikation nicht gelöscht.
Verglichen werden nur die Revisionsnummern. Höhere Revisionsnummer
des Dokuments beim Master = Client wird aktualisiert.
Ein gelöschtes Dokument bleibt weiterhin in der Datenbank.
Löschen ist eine Änderung an einem Dokument (_deleted:true), und
gelöschte Dokumente werden repliziert.
Oliver Kurowski, @okurow
54. Replikation
Start einer Replikation über POST Befehl an _replicate
$ curl -X POST http://localhost:5984/_replicate -H "Content-type:application/json"
-d '{"source":"datenbank_a","target":"datenbank_b"}'
{"ok":true,"session_id":"b4ecde6f3b4a3948e51a409894b18a5c","source_last_seq":1,"repli
cation_id_version":2,"history":[{"session_id":"b4ecde6f3b4a3948e51a409894b18a5c","star
t_time":„Sun, 10 Jun 2012 09:55:16 GMT","end_time":„Sun, 10 Jun 2012 09:55:16
GMT","start_last_seq":0,"end_last_seq":1,"recorded_seq":1,"missing_checked":1,"missing
_found":1,"docs_read":1,"docs_written":1,"doc_write_failures":0}]}
Oliver Kurowski, @okurow
55. Replikation
Oder durch Eintrag in die _replicator Datenbank
$ curl -X PUT http://localhost:5984/_replicator/einmalig
-d {"source":"datenbank_a","target":"datenbank_b"}'
{"ok":true,"id":"einmalig","rev":"1-57c8e9e3949e9fa48c135f8cdae3d88e"}
Dieses Dokument nach der Replikation:
{ "_id": "einmalig",
"_rev": "3-4700e5caef6496219e032322427bca43",
"source": "datenbank_a",
"target": "datenbank_b",
"owner": null,
"_replication_state": "completed",
"_replication_state_time": "2012-06-10T03:05:35-07:00",
"_replication_id": "44534eb9bb71658fe1698fc69d62f88b",
"_replication_stats": {
"revisions_checked": 2,
"missing_revisions_found": 1,
"docs_read": 1,
"docs_written": 1,
"doc_write_failures": 0,
"checkpointed_source_seq": 3 } }
Oliver Kurowski, @okurow
56. Replikation
Besonderheiten bei Replikationen:
Continuous Replication:
Replikationen müssen nicht einzeln angestoßen werden, Änderungen
werden kontinuierlich weitergegeben
Named Document Replication:
Nur einzeln benannte Dokumente werden repliziert
Auch Designdokumente können repliziert werden. Bei Verwendung von
Applikation in der CouchDB einfaches Deployment der App über viele
Datenbanken automatisch möglich.
Oliver Kurowski, @okurow
57. Replikation
Ein Highlight:
Filtered Replication:
Eine Funktion erlaubt/ verhindert die Replikation von Dokumenten
{
“_id“:“_design/filterfunktionen“,
“filters“: {
“ab18“:“function(doc,req) {
if(doc.alter && doc.alter>17) {
return true;
} else {
return false;
}
}“
}
}
$ curl -X PUT http://localhost:5984/_replicator/einmalig
-d {"source":"datenbank_a","target":"datenbank_b“, “filter”:”filterfunktionen/ab18”}'
Oliver Kurowski, @okurow