{% include anchor.html edit="true" title="Replicate a database" hash="replication" %} {% highlight js %} PouchDB.replicate(source, target, [options]) {% endhighlight %} Replicate data from `source` to `target`. Both the `source` and `target` can be a PouchDB instance or a string representing a CouchDB database URL or the name of a local PouchDB database. If `options.live` is `true`, then this will track future changes and also replicate them automatically. This method returns an object with the method `cancel()`, which you call if you want to cancel live replication. Replication is an [event emitter][] like [changes()](#changes) and emits the `'complete'`, `'active'`, `'paused'`, `'change'`, `'denied'` and `'error'` events. ### Options All options default to `false` unless otherwise specified. * `options.live`: If `true`, starts subscribing to future changes in the `source` database and continue replicating them. * `options.retry`: If `true` will attempt to retry replications in the case of failure (due to being offline), using a backoff algorithm that retries at longer and longer intervals until a connection is re-established, with a maximum delay of 10 minutes. Only applicable if `options.live` is also `true`. **Filtering Options:** * `options.filter`: Reference a filter function from a design document to selectively get updates. To use a view function, pass `_view` here and provide a reference to the view function in `options.view`. See [filtered replication](#filtered-replication) for details. * `options.doc_ids`: Only show changes for docs with these ids (array of strings). * `options.query_params`: Object containing properties that are passed to the filter function, e.g. `{"foo":"bar"}`, where `"bar"` will be available in the filter function as `params.query.foo`. To access the `params`, define your filter function like `function (doc, params) {/* ... */}`. * `options.view`: Specify a view function (e.g. `'design_doc_name/view_name'` or `'view_name'` as shorthand for `'view_name/view_name'`) to act as a filter. Documents counted as "passed" for a view filter if a map function emits at least one record for them. **Note**: `options.filter` must be set to `'_view'` for this option to work. **Advanced Options:** * `options.since`: Replicate changes after the given sequence number. * `options.heartbeat`: Configure the heartbeat supported by CouchDB which keeps the change connection alive. * `options.timeout`: Request timeout (in milliseconds). * `options.batch_size`: Number of change feed items to process at a time. Defaults to 100. This affects the number of docs and attachments held in memory and the number sent at a time to the target server. You may need to adjust downward if targeting devices with low amounts of memory (e.g. phones) or if the documents and/or attachments are large in size or if there are many conflicted revisions. If your documents are small in size, then increasing this number will probably speed replication up. * `options.batches_limit`: Number of batches to process at a time. Defaults to 10. This (along wtih `batch_size`) controls how many docs are kept in memory at a time, so the maximum docs in memory at once would equal `batch_size` × `batches_limit`. * `options.back_off_function`: backoff function to be used in `retry` replication. This is a function that takes the current backoff as input (or 0 the first time) and returns a new backoff in milliseconds. You can use this to tweak when and how replication will try to reconnect to a remote database when the user goes offline. Defaults to a function that chooses a random backoff between 0 and 2 seconds and doubles every time it fails to connect. The default delay will never exceed 10 minutes. (See [Customizing retry replication](#customizing-retry-replication) below.) #### Example Usage: {% highlight js %} var rep = PouchDB.replicate('mydb', 'http://localhost:5984/mydb', { live: true, retry: true }).on('change', function (info) { // handle change }).on('paused', function (err) { // replication paused (e.g. replication up to date, user went offline) }).on('active', function () { // replicate resumed (e.g. new changes replicating, user went back online) }).on('denied', function (err) { // a document failed to replicate (e.g. due to permissions) }).on('complete', function (info) { // handle complete }).on('error', function (err) { // handle error }); rep.cancel(); // whenever you want to cancel {% endhighlight %} There are also shorthands for replication given existing PouchDB objects. These behave the same as `PouchDB.replicate()`: {% highlight js %} db.replicate.to(remoteDB, [options]); // or db.replicate.from(remoteDB, [options]); {% endhighlight %} The `remoteDB` can either be a string or a `PouchDB` object. If you have special ajax options on a remote database, you will want to use `PouchDB` objects instead of strings, so that the options are used. #### Replication events * __`change`__ (`info`) - This event fires when the replication has written a new document. `info` will contain details about the change. `info.docs` will contain the docs involved in that change. See below for an example response. * __`complete`__ (`info`) - This event fires when replication is completed or cancelled. In a live replication, only cancelling the replication should trigger this event. `info` will contain details about the replication. See below for an example response. * __`paused`__ (`err`) - This event fires when the replication is paused, either because a live replication is waiting for changes, or replication has temporarily failed, with `err`, and is attempting to resume. * __`active`__ - This event fires when the replication starts actively processing changes; e.g. when it recovers from an error or new changes are available. * __`denied`__ (`err`) - This event fires if a document failed to replicate due to validation or authorization errors. * __`error`__ (`err`) - This event is fired when the replication is stopped due to an unrecoverable failure. If `retry` is `false`, this will also fire when the user goes offline or another network error occurs (so you can handle retries yourself, if you want). #### Single-shot As with [changes()](#changes), you can also omit `live`, in which case you can use `replicate()` in the callback/promise style and it will be treated as a single-shot operation. {% include code/start.html id="replication1" type="callback" %} {% highlight js %} db.replicate.to(remote, function (err, result) { if (err) { return console.log(err); } // handle 'completed' result }); {% endhighlight %} {% include code/end.html %} {% include code/start.html id="replication1" type="async" %} {% highlight js %} try { var result = await db.replicate.to(remote); } catch (err) { console.log(err); } {% endhighlight %} {% include code/end.html %} {% include code/start.html id="replication1" type="promise" %} {% highlight js %} db.replicate.to(remote).then(function (result) { // handle 'completed' result }).catch(function (err) { console.log(err); }); {% endhighlight %} {% include code/end.html %} For non-live replications, the returned object is also an event emitter as well as a promise, and you can use all the events described above (except for `'paused'` and `'active'`, which only apply to `retry` replications). #### Example Response: Example response in the `'change'` listener: {% highlight js %} { "doc_write_failures": 0, "docs_read": 1, "docs_written": 1, "errors": [], "last_seq": 1, "ok": true, "start_time": "Fri May 16 2014 18:23:12 GMT-0700 (PDT)", "docs": [ { _id: 'docId', _rev: '1-e798a1a7eb4247b399dbfec84ca699d4', and: 'data' } ] } {% endhighlight %} Example response in the `'complete'` listener: {% highlight js %} { "doc_write_failures": 0, "docs_read": 2, "docs_written": 2, "end_time": "Fri May 16 2014 18:26:00 GMT-0700 (PDT)", "errors": [], "last_seq": 2, "ok": true, "start_time": "Fri May 16 2014 18:26:00 GMT-0700 (PDT)", "status": "complete" } {% endhighlight %} Note that replication is supported for both local and remote databases. So you can replicate from local to local or from remote to remote. However, if you replicate from remote to remote, then the changes will flow through PouchDB. If you want to trigger a server-initiated replication, please use regular ajax to POST to the CouchDB `_replicate` endpoint, as described [in the CouchDB docs](https://wiki.apache.org/couchdb/Replication). #### Filtered replication As with [changes()](#changes), you can filter from the source database using: * an ad-hoc `filter` function * an array of `doc_ids` * a `filter` function inside of a design document * a `filter` function inside of a design document, with `query_params` * a `view` function inside of a design document If you are replicating from a remote CouchDB, then the first method will run client-side, whereas the last four will filter on the server side. Therefore the last four should be preferred, especially if the database is large, because you want to send as few documents over the wire as possible. You should also beware trying to use filtered replication to enforce security, e.g. to partition a database per user. A better strategy is the ["one database per user" method](https://github.com/nolanlawson/pouchdb-authentication#couchdb-authentication-recipes). {% include alert/start.html variant="warning" %} {% markdown %} **Deleting filtered docs**: When you use filtered replication, you should avoid using `remove()` to delete documents, because that removes all their fields as well, which means they might not pass the filter function anymore, causing the deleted revision to not be replicated. Instead, set the `doc._deleted` flag to `true` and then use `put()` or `bulkDocs()`. {% endmarkdown %} {% include alert/end.html %} #### Filtering examples In these examples, we'll work with some mammals. Let's imagine our docs are: {% highlight js %} [ {_id: 'a', name: 'Kangaroo', type: 'marsupial'}, {_id: 'b', name: 'Koala', type: 'marsupial'}, {_id: 'c', name: 'Platypus', type: 'monotreme'} ] {% endhighlight %} Here are 5 examples using the 5 different systems. **Example 1: Ad-hoc `filter` function** *Warning*: this runs client-side, if you are replicating from a remote database. Filter by `type === 'marsupial'`: {% highlight js %} remote.replicate.to(local, { filter: function (doc) { return doc.type === 'marsupial'; } }); {% endhighlight %} **Example 2: Array of `doc_ids`** Filter documents with `_id`s `['a', 'c']`. {% highlight js %} remote.replicate.to(local, { doc_ids: ['a', 'c'] }); {% endhighlight %} **Example 3: `filter` function inside of a design document** First `put()` a design document in the remote database: {% highlight js %} { _id: '_design/mydesign', filters: { myfilter: function (doc) { return doc.type === 'marsupial'; }.toString() } } {% endhighlight %} Then filter by `type === 'marsupial'`: {% highlight js %} remote.replicate.to(local, { filter: 'mydesign/myfilter' }); {% endhighlight %} **Example 4: `filter` function inside of a design document, with `query_params`** This is the most powerful way to filter, because it allows you to pass in arbitrary options to your filter function. First `put()` a design document in the remote database: {% highlight js %} { _id: '_design/mydesign', filters: { myfilter: function (doc, req) { return doc.type === req.query.type; }.toString() } } {% endhighlight %} Then filter by `type === 'marsupial'`: {% highlight js %} remote.replicate.to(local, { filter: 'mydesign/myfilter', query_params: {type: 'marsupial'} }); {% endhighlight %} **Example 5: `view` function inside of a design document** This doesn't really offer any advantages compared to the previous two methods, unless you are already using a `view` for map/reduce queries, and you want to reuse it. Any documents that `emit()` anything will be considered to have passed this filter method. First `put()` a design document in the remote database: {% highlight js %} { _id: '_design/mydesign', views: { myview: { map: function(doc) { if (doc.type === 'marsupial') { emit(doc._id); } }.toString() } } } {% endhighlight %} Then filter by `type === 'marsupial'`: {% highlight js %} remote.replicate.to(local, { filter: '_view', view: 'mydesign/myview' }); {% endhighlight %} #### Customizing retry replication During `retry` replication, you can customize the backoff function that determines how long to wait before reconnecting when the user goes offline. Here's a simple backoff function that starts at 1000 milliseconds and triples it every time a remote request fails: {% highlight js %} db.replicate.to(remote, { live: true, retry: true, back_off_function: function (delay) { if (delay === 0) { return 1000; } return delay * 3; } }); {% endhighlight %} The first time a request fails, this function will receive 0 as input. The next time it fails, 1000 will be passed in, then 3000, then 9000, etc. When the user comes back online, the `delay` goes back to 0. By default, PouchDB uses a backoff function that chooses a random starting number between 0 and 2000 milliseconds and will roughly double every time, with some randommness to prevent client requests from occurring simultaneously.