GitHub

API Reference

API overview

PouchDB has an asynchronous API, supporting both callbacks and promises.

Most of the API is exposed as:

db.doSomething(args..., [options], [callback])

… where both the options and callback are optional.

Callbacks use the standard Node.js idiom of:

function(error, result) { /* ... */ }

… where the error will be undefined if there’s no error.

If you don’t specify a callback, then the API returns a promise. In supported browsers, native promises are used, falling back to the minimal library lie as needed. In Node.js, promises come from Bluebird.

Using Ionic/Angular? You can wrap PouchDB promises in $q.when(). This will notify Angular to update the UI when the PouchDB promise has resolved.

For more info, check out the guide to asynchronous code.

Create a database

new PouchDB([name], [options])

This method creates a database or opens an existing one. If you use a URL like 'http://domain.com/dbname', then PouchDB will work as a client to an online CouchDB instance. Otherwise it will create a local database using whatever backend is present.

Options

  • name: You can omit the name argument and specify it via options instead. Note that the name is required.

Options for local databases:

  • auto_compaction: This turns on auto compaction, which means compact() is called after every change to the database. Defaults to false.
  • adapter: One of 'idb', 'leveldb', 'websql', or 'http'. If unspecified, PouchDB will infer this automatically, preferring IndexedDB to WebSQL in browsers that support both (i.e. Chrome, Opera and Android 4.4+).

Options for remote databases:

  • ajax: (Remote databases only.) Ajax requester options. For instance, passing in the options {ajax: {timeout: 10000}} will allow you to set the max timeout for an HTTP request. These are passed ver batim to request (in Node.js) or a request shim (in the browser), with the exception of:
  • ajax.cache: Appends a random string to the end of all HTTP GET requests to avoid them being cached on IE. Set this to true to prevent this happening.
  • ajax.headers: The ajax.headers option allows you to customise headers that are sent to the remote HTTP Server.
  • auth.username + auth.password: You can specify HTTP auth parameters either by using a database with a name in the form http://user:pass@host/name or via the auth.username + auth.password options.

WebSQL-only options:

  • size: amount in MB to request for storage, which you will need if you are storing >5MB in order to avoid storage limit errors on iOS/Safari. Details here.

SQLite Plugin-only options:

Notes:

  1. In IndexedDB and WebSQL, PouchDB will use _pouch_ to prefix the internal database names. Do not manually create databases with the same prefix.
  2. When acting as a client on Node, any other options given will be passed to request.
  3. When using the 'leveldb' adapter (the default on Node), any other options given will be passed to levelup. The storage layer of leveldb can be replaced by passing a level backend factory (such as MemDOWN) as options.db. The rest of the supported options are documented here.

Example Usage:

var db = new PouchDB('dbname');
// or
var db = new PouchDB('http://localhost:5984/dbname');

Create a WebSQL-only Pouch (e.g. when using the SQLite Plugin for Cordova/PhoneGap):

var db = new PouchDB('dbname', {adapter : 'websql'});

Create an in-memory Pouch (in Node):

var db = new PouchDB('dbname', {db : require('memdown')});

Create a remote PouchDB with special Ajax options:

var db = new PouchDB('http://example.com/dbname', {
  ajax: {
    cache: false,
    timeout: 10000,
    headers: {
      'X-Some-Special-Header': 'foo'
    },
  },
  auth: {
    username: 'mysecretusername',
    password: 'mysecretpassword'
  }
});

For more info, check out adapters.

Delete a database

db.destroy([options], [callback])

Delete the database. Note that this has no impact on other replicated databases.

Options

Example Usage

Callback:

db.destroy(function (error) {
  if (error) {
    return console.log(error);
  } else {
    // success
  }
});

Promise:

db.destroy().then(function () {
  // success
}).catch(function (error) {
  console.log(error);
});

Create/update a document

Using db.put()

db.put(doc, [docId], [docRev], [options], [callback])

Create a new document or update an existing document. If the document already exists, you must specify its revision _rev, otherwise a conflict will occur.

There are some restrictions on valid property names of the documents. These are explained here.

Example Usage:

Create a new doc with an _id of 'mydoc':

Callback:

db.put({
  _id: 'mydoc',
  title: 'Heroes'
}, function(err, response) {
  if (err) { return console.log(err); }
  // handle response
});

Promise:

db.put({
  _id: 'mydoc',
  title: 'Heroes'
}).then(function (response) {
  // handle response
}).catch(function (err) {
  console.log(err);
});

You can update an existing doc using _rev:

Callback:

db.get('mydoc', function(err, doc) {
  if (err) { return console.log(err); }
  db.put({
    _id: 'mydoc',
    _rev: doc._rev,
    title: "Let's Dance"
  }, function(err, response) {
    if (err) { return console.log(err); }
    // handle response
  });
});

Promise:

db.get('mydoc').then(function(doc) {
  return db.put({
    _id: 'mydoc',
    _rev: doc._rev,
    title: "Let's Dance"
  });
}).then(function(response) {
  // handle response
}).catch(function (err) {
  console.log(err);
});

Instead of including the _id and _rev in the document, you can also pass them in as options:

Callback:

db.get('mydoc', function(err, doc) {
  if (err) { return console.log(err); }
  db.put({
    title: "Sound and Vision"
  }, 'mydoc', doc._rev, function(err, response) {
    if (err) { return console.log(err); }
    // handle response
  });
});

Promise:

db.get('mydoc').then(function(doc) {
  return db.put({
    title: "Sound and Vision"
  }, 'mydoc', doc._rev,);
}).then(function(response) {
  // handle response
}).catch(function (err) {
  console.log(err);
});

Example Response:

{
  "ok": true,
  "id": "mydoc",
  "rev": "1-A6157A5EA545C99B00FF904EEF05FD9F"
}

The response contains the id of the document, the new rev, and an ok to reassure you that everything is okay.

Using db.post()

db.post(doc, [options], [callback])

Create a new document and let PouchDB auto-generate an _id for it.

Example Usage:

Callback:

db.post({
  title: 'Ziggy Stardust'
}, function (err, response) {
  if (err) { return console.log(err); }
  // handle response
});

Promise:

db.post({
  title: 'Ziggy Stardust'
}).then(function (response) {
  // handle response
}).catch(function (err) {
  console.log(err);
});

Example Response:

{
  "ok" : true,
  "id" : "8A2C3761-FFD5-4770-9B8C-38C33CED300A",
  "rev" : "1-d3a8e0e5aa7c8fff0c376dac2d8a4007"
}

Put vs. post: The basic rule of thumb is: put() new documents with an _id, post() new documents without an _id.

You should also prefer put() to post(), because when you post(), you are missing an opportunity to use allDocs() to sort documents by _id (because your _ids are random). For more info, read the PouchDB pro tips.

Fetch a document

db.get(docId, [options], [callback])

Retrieves a document, specified by docId.

Options

All options default to false unless otherwise specified.

  • options.rev: Fetch specific revision of a document. Defaults to winning revision (see the CouchDB guide).
  • options.revs: Include revision history of the document.
  • options.revs_info: Include a list of revisions of the document, and their availability.
  • options.open_revs: Fetch all leaf revisions if open_revs="all" or fetch all leaf revisions specified in open_revs array. Leaves will be returned in the same order as specified in input array.
  • options.conflicts: If specified, conflicting leaf revisions will be attached in _conflicts array.
  • options.attachments: Include attachment data.
  • options.local_seq (DEPRECATED): Include sequence number of the revision in the database, this will be removed in the next major version.
  • options.ajax: An object of options to be sent to the ajax requester. In Node they are sent verbatim to request with the exception of:
  • options.ajax.cache: Appends a random string to the end of all HTTP GET requests to avoid them being cached on IE. Set this to true to prevent this happening.

Example Usage:

Callback:

db.get('mydoc', function(err, doc) {
  if (err) { return console.log(err); }
  // handle doc
});

Promise:

db.get('mydoc').then(function (doc) {
  // handle doc
}).catch(function (err) {
  console.log(err);
});

Example Response:

{
  "_id": "mydoc",
  "_rev": "1-A6157A5EA545C99B00FF904EEF05FD9F"
  "title": "Rock and Roll Heart",
}

The response contains the document as it is stored in the database, along with its _id and _rev.

Delete a document

db.remove(doc, [options], [callback])

Or:

db.remove(docId, docRev, [options], [callback])

Deletes the document. doc is required to be a document with at least an _id and a _rev property. Sending the full document will work as well.

Example Usage:

Callback:

db.get('mydoc', function(err, doc) {
  if (err) { return console.log(err); }
  db.remove(doc, function(err, response) {
    if (err) { return console.log(err); }
    // handle response
  });
});

Promise:

db.get('mydoc').then(function(doc) {
  return db.remove(doc);
}).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Example Response:

{
  "ok": true,
  "id": "mydoc",
  "rev": "2-9AF304BE281790604D1D8A4B0F4C9ADB"
}

You can also delete a document by just providing an id and rev:

Callback:

db.get('mydoc', function(err, doc) {
  if (err) { return console.log(err); }
  db.remove(doc._id, doc._rev, function(err, response) {
    if (err) { return console.log(err); }
    // handle response
  });
});

Promise:

db.get('mydoc').then(function(doc) {
  return db.remove(doc._id, doc._rev);
}).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

You can also delete a document by using put() with {_deleted: true}:

Callback:

db.get('mydoc', function(err, doc) {
  if (err) { return console.log(err); }
  doc._deleted = true;
  db.put(doc, function(err, response) {
    if (err) { return console.log(err); }
    // handle response
  });
});

Promise:

db.get('mydoc').then(function(doc) {
  doc._deleted = true;
  return db.put(doc);
}).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Create/update a batch of documents

db.bulkDocs(docs, [options], [callback])

Create, update or delete multiple documents. The docs argument is an array of documents.

If you omit an _id parameter on a given document, the database will create a new document and assign the ID for you. To update a document, you must include both an _id parameter and a _rev parameter, which should match the ID and revision of the document on which to base your updates. Finally, to delete a document, include a _deleted parameter with the value true.

Example Usage:

Put some new docs, providing the _ids:

Callback:

db.bulkDocs([
  {title : 'Lisa Says', _id: 'doc1'},
  {title : 'Space Oddity', _id: 'doc2'}
], function(err, response) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

db.bulkDocs([
  {title : 'Lisa Says', _id: 'doc1'},
  {title : 'Space Oddity', _id: 'doc2'}
]).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Post some new docs and auto-generate the _ids:

Callback:

db.bulkDocs([
  {title : 'Lisa Says'},
  {title : 'Space Oddity'}
], function(err, response) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

db.bulkDocs([
  {title : 'Lisa Says'},
  {title : 'Space Oddity'}
]).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Example Response:

[
  {
    "ok": true,
    "id": "doc1",
    "rev": "1-84abc2a942007bee7cf55007cba56198"
  },
  {
    "ok": true,
    "id": "doc2",
    "rev": "1-7b80fc50b6af7a905f368670429a757e"
  }
]

The response contains an array of the familiar ok/rev/id from the put()/post() API. If there are any errors, they will be provided individually like so:

[
  { status: 409,
    name: 'conflict',
    message: 'Document update conflict',
    error: true 
  }
]

Note that bulkDocs() is not transactional, and that you may get back a mixed array of errors/non-errors. In CouchDB/PouchDB, the smallest atomic unit is the document.

Bulk update/delete:

You can also use bulkDocs() to update/delete many documents at once:

Callback:

db.bulkDocs([
  {
    title  : 'Lisa Says',
    artist : 'Velvet Underground',
    _id    : "doc1",
    _rev   : "1-84abc2a942007bee7cf55007cba56198"
  },
  {
    title  : 'Space Oddity',
    artist : 'David Bowie',
    _id    : "doc2",
    _rev   : "1-7b80fc50b6af7a905f368670429a757e"
  }
], function(err, response) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

db.bulkDocs([
  {
    title  : 'Lisa Says',
    artist : 'Velvet Underground',
    _id    : "doc1",
    _rev   : "1-84abc2a942007bee7cf55007cba56198"
  },
  {
    title  : 'Space Oddity',
    artist : 'David Bowie',
    _id    : "doc2",
    _rev   : "1-7b80fc50b6af7a905f368670429a757e"
  }
]).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Or delete them:

Callback:

db.bulkDocs([
  {
    title    : 'Lisa Says',
    _deleted : true,
    _id      : "doc1",
    _rev     : "1-84abc2a942007bee7cf55007cba56198"
  },
  {
    title    : 'Space Oddity',
    _deleted : true,
    _id      : "doc2",
    _rev     : "1-7b80fc50b6af7a905f368670429a757e"
  }
], function(err, response) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

db.bulkDocs([
  {
    title    : 'Lisa Says',
    _deleted : true,
    _id      : "doc1",
    _rev     : "1-84abc2a942007bee7cf55007cba56198"
  },
  {
    title    : 'Space Oddity',
    _deleted : true,
    _id      : "doc2",
    _rev     : "1-7b80fc50b6af7a905f368670429a757e"
  }
]).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Note: You can also specify a new_edits property on the options object that when set to false allows you to post and overwrite existing documents. Normally only the replication algorithm needs to do this.

Fetch a batch of documents

db.allDocs([options], [callback])

Fetch multiple documents, indexed and sorted by the _id. Deleted documents are only included if options.keys is specified.

Options

All options default to false unless otherwise specified.

  • options.include_docs: Include the document itself in each row in the doc field. Otherwise by default you only get the _id and _rev properties.
    • options.conflicts: Include conflict information in the _conflicts field of a doc.
    • options.attachments: Include attachment data as base64-encoded string.
  • options.startkey & options.endkey: Get documents with IDs in a certain range (inclusive/inclusive).
  • options.inclusive_end: Include documents having an ID equal to the given options.endkey. Default: true.
  • options.limit: Maximum number of documents to return.
  • options.skip: Number of docs to skip before returning (warning: poor performance on IndexedDB/LevelDB!).
  • options.descending: Reverse the order of the output documents.
  • options.key: Only return documents with IDs matching this string key.
  • options.keys: Array of string keys to fetch in a single shot.
    • Neither startkey nor endkey can be specified with this option.
    • The rows are returned in the same order as the supplied keys array.
    • The row for a deleted document will have the revision ID of the deletion, and an extra key "deleted":true in the value property.
    • The row for a nonexistent document will just contain an "error" property with the value "not_found".
    • For details, see the CouchDB query options documentation.

Notes: For pagination, options.limit and options.skip are also available, but the same performance concerns as in CouchDB apply. Use the startkey/endkey pattern instead.

Example Usage:

Callback:

db.allDocs({
  include_docs: true, 
  attachments: true
}, function(err, response) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

db.allDocs({
  include_docs: true, 
  attachments: true
}).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Example Response:

{
  "offset": 0,
  "total_rows": 1,
  "rows": [{
    "doc": {
      "_id": "0B3358C1-BA4B-4186-8795-9024203EB7DD",
      "_rev": "1-5782E71F1E4BF698FA3793D9D5A96393",
      "title": "Sound and Vision",
      "_attachments": {
      	"attachment/its-id": {
      	  "content_type": "image/jpg",
      	  "data": "R0lGODlhAQABAIAAAP7//wAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==",
      	  "digest": "md5-57e396baedfe1a034590339082b9abce"
      	}
      }
    },
   "id": "0B3358C1-BA4B-4186-8795-9024203EB7DD",
   "key": "0B3358C1-BA4B-4186-8795-9024203EB7DD",
   "value": {
    "rev": "1-5782E71F1E4BF698FA3793D9D5A96393"
   }
 }]
}

In the response, you have three things:

  • total_rows the total number of non-deleted documents in the database
  • offset the skip if provided, or in CouchDB the actual offset
  • rows: rows containing the documents, or just the _id/_revs if you didn’t set include_docs to true.

You can use startkey/endkey to find all docs in a range:

Callback:

db.allDocs({
  include_docs: true, 
  attachments: true,
  startkey: 'bar',
  endkey: 'quux'
}, function(err, response) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

db.allDocs({
  include_docs: true, 
  attachments: true,
  startkey: 'bar',
  endkey: 'quux'
}).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

This will return all docs with _ids between 'bar' and 'quux'.

You can do prefix search in allDocs() – i.e. “give me all the documents whose _ids start with 'foo'” – by using the special high Unicode character '\uffff':

Callback:

db.allDocs({
  include_docs: true, 
  attachments: true,
  startkey: 'foo',
  endkey: 'foo\uffff'
}, function(err, response) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

db.allDocs({
  include_docs: true, 
  attachments: true,
  startkey: 'foo',
  endkey: 'foo\uffff'
}).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

This works because CouchDB/PouchDB _ids are sorted lexicographically.

Listen to database changes

db.changes(options)

A list of changes made to documents in the database, in the order they were made. It returns an object with the method cancel(), which you call if you don’t want to listen to new changes anymore.

It is an event emitter and will emit a 'change' event on each document change, a 'complete' event when all the changes have been processed, and an 'error' event when an error occurs. In addition to the 'change' event, any change will also emit a 'create', 'update', or 'delete' event.

Options

All options default to false unless otherwise specified.

  • options.live: Does “live” changes, using CouchDB’s _longpoll_ feed if remote.
  • options.include_docs: Include the associated document with each change.
    • options.conflicts: Include conflicts.
    • options.attachments: Include attachments.
  • options.descending: Reverse the order of the output documents.
  • options.since: Start the results from the change immediately after the given sequence number. You can also pass 'now' if you want only new changes (when live is true).
  • options.limit: Limit the number of results to this number.
  • options.timeout: Request timeout (in milliseconds).

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 changes 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') 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.returnDocs: Is available for non-http databases and defaults to true. Passing false prevents the changes feed from keeping all the documents in memory – in other words complete always has an empty results array, and the change event is the only way to get the event. Useful for large change sets where otherwise you would run out of memory.
  • options.batch_size: Only available for http databases, this configures how many changes to fetch at a time. Increasing this can reduce the number of requests made. Default is 25.
  • options.style: Specifies how many revisions are returned in the changes array. The default, 'main_only', will only return the current “winning” revision; 'all_docs' will return all leaf revisions (including conflicts and deleted former conflicts). Most likely you won’t need this unless you’re writing a replicator.

Example Usage:

var changes = db.changes({
  since: 'now',
  live: true,
  include_docs: true
}).on('change', function(change) {
  // handle change
}).on('complete', function(info) {
  // changes() was canceled
}).on('error', function (err) {
  console.log(err);
});

changes.cancel(); // whenever you want to cancel

Example Response:

{
  "id":"somestuff",
  "seq":21,
  "changes":[{
    "rev":"1-8e6e4c0beac3ec54b27d1df75c7183a8"
  }],
  "doc":{
    "title":"Ch-Ch-Ch-Ch-Changes",
    "_id":"someDocId",
    "_rev":"1-8e6e4c0beac3ec54b27d1df75c7183a8"
  }
}

Change events

  • change (info) - This event fires when a change has been found. info will contain details about the change, such as whether it was deleted and what the new _rev is. info.doc will contain the doc if you set include_docs to true. See below for an example response.
  • complete (info) - This event fires when all changes have been read. In live changes, only cancelling the changes should trigger this event. info.results will contain the list of changes. See below for an example.
  • error (err) - This event is fired when the replication is stopped due to an unrecoverable failure.

Example response

Example response in the 'change' listener (using {include_docs: true}):

{ id: 'doc1',
  changes: [ { rev: '1-9152679630cc461b9477792d93b83eae' } ],
  doc: { 
    _id: 'doc1', 
    _rev: '1-9152679630cc461b9477792d93b83eae' 
  },
  seq: 1 
}

Example response in the 'change' listener when a doc was deleted:

{ id: 'doc2',
  changes: [ { rev: '2-9b50a4b63008378e8d0718a9ad05c7af' } ],
  doc: { _id: 'doc2',
    _rev: '2-9b50a4b63008378e8d0718a9ad05c7af',
    _deleted: true 
  },
  deleted: true,
  seq: 3
}

Example response in the 'complete' listener:

{
  "results": [
    {
      "id": "doc1",
      "changes": [ { "rev": "1-9152679630cc461b9477792d93b83eae" } ],
      "doc": {
        "_id": "doc1",
        "_rev": "1-9152679630cc461b9477792d93b83eae"
      },
      "seq": 1
    },
    {
      "id": "doc2",
      "changes": [ { "rev": "2-9b50a4b63008378e8d0718a9ad05c7af" } ],
      "doc": {
        "_id": "doc2",
        "_rev": "2-9b50a4b63008378e8d0718a9ad05c7af",
        "_deleted": true
      },
      "deleted": true,
      "seq": 3
    }
  ],
  "last_seq": 3
}

seq and last_seq correspond to the overall sequence number of the entire database, and it’s what is passed in when using since (except for the special 'now'). It is the primary key for the changes feed, and is also used as a checkpointer by the replication algorithm.

Single-shot

If you don’t specify {live: true}, then you can also use changes() in the standard callback/promise style, and it will be treated as a single-shot request, which returns a list of the changes (i.e. what the 'complete' event emits):

Callback:

db.changes({
  limit: 10,
  since: 0
}, function (err, response) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

db.changes({
  limit: 10,
  since: 0
}).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Example Response:

{
  "results": [{
    "id": "0B3358C1-BA4B-4186-8795-9024203EB7DD",
    "seq": 1,
    "changes": [{
      "rev": "1-5782E71F1E4BF698FA3793D9D5A96393"
    }]
  }, {
    "id": "mydoc",
    "seq": 2,
    "changes": [{
      "rev": "1-A6157A5EA545C99B00FF904EEF05FD9F"
    }]
  }, {
    "id": "otherdoc",
    "seq": 3,
    "changes": [{
      "rev": "1-3753476B70A49EA4D8C9039E7B04254C"
    }]
  }, {
    "id": "828124B9-3973-4AF3-9DFD-A94CE4544005",
    "seq": 4,
    "changes": [{
      "rev": "1-A8BC08745E62E58830CA066D99E5F457"
    }]
  }]
}

When live is false, the returned object is also an event emitter as well as a promise, and will fire the 'complete' event when the results are ready.

Note that this 'complete' event only fires when you aren’t doing live changes. With live changes, use the 'paused' event instead.

Filtered changes

As with replicate(), you can filter 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 running changes() on 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.

If you are running changes() on a local PouchDB, then obviously all five methods will run client-side. There are also no performance benefits to using any of the five, so can also just filter yourself, in your own on('change') handler. These methods are implemented in PouchDB purely for consistency with CouchDB.

Filtering examples

In these examples, we’ll work with some mammals. Let’s imagine our docs are:

[
  {_id: 'a', name: 'Kangaroo', type: 'marsupial'},
  {_id: 'b', name: 'Koala', type: 'marsupial'},
  {_id: 'c', name: 'Platypus', type: 'monotreme'}
]

Here are 5 examples using the 5 different systems.

Example 1: Ad-hoc filter function

Warning: this runs client-side, if the database is remote.

Filter by type === 'marsupial':

db.changes({
  filter: function (doc) {
    return doc.type === 'marsupial';
  }
});

Example 2: Array of doc_ids

Filter documents with _ids ['a', 'c'].

db.changes({
  doc_ids: ['a', 'c']
});

Example 3: filter function inside of a design document

First put() a design document:

{
  _id: '_design/mydesign',
  filters: {
    myfilter: function (doc) {
      return doc.type === 'marsupial';
    }.toString()
  }
}

Then filter by type === 'marsupial':

db.changes({
  filter: 'mydesign/myfilter'
});

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:

{
  _id: '_design/mydesign',
  filters: {
    myfilter: function (doc, req) {
      return doc.type === req.query.type;
    }.toString()
  }
}

Then filter by type === 'marsupial':

db.changes({
  filter: 'mydesign/myfilter',
  query_params: {type: 'marsupial'}
});

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:

{
  _id: '_design/mydesign',
  views: {
    myview: function (doc) {
      if (doc.type === 'marsupial') {
        emit(doc._id);
      }
    }.toString()
  }
}

Then filter by type === 'marsupial':

db.changes({
  filter: '_view',
  view: 'mydesign/myview'
});

Replicate a database

PouchDB.replicate(source, target, [options])

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() 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. 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 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') 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.batch_size: Number of documents to process at a time. Defaults to 100. This affects the number of docs 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 are large in size (e.g. with attachments). 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. (See Customizing retry replication below.)

Example Usage:

var rep = PouchDB.replicate('mydb', 'http://localhost:5984/mydb', {
  live: true,
  retry: true
}).on('change', function (info) {
  // handle change
}).on('paused', function () {
  // replication paused (e.g. user went offline)
}).on('active', function () {
  // replicate resumed (e.g. user went back online)
}).on('denied', function (info) {
  // 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

There are also shorthands for replication given existing PouchDB objects. These behave the same as PouchDB.replicate():

db.replicate.to(remoteDB, [options]);
// or
db.replicate.from(remoteDB, [options]);

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.doc will contain the doc if you set include_docs to true. 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).
  • uptodate (deprecated) - This event fires when a live replication has caught up and is waiting on future changes. This should be replaced by using the paused event.

Single-shot

As with 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.

Callback:

db.replicate.to(remote, function (err, result) {
  if (err) { return console.log(err); }
  // handle 'completed' result
});

Promise:

db.replicate.to(remote).then(function (result) {
  // handle 'completed' result
}).catch(function (err) {
  console.log(err);
});

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:

{
  "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)"
}

Example response in the 'complete' listener:

{
  "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"
}

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.

Filtered replication

As with 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.

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().

Filtering examples

In these examples, we’ll work with some mammals. Let’s imagine our docs are:

[
  {_id: 'a', name: 'Kangaroo', type: 'marsupial'},
  {_id: 'b', name: 'Koala', type: 'marsupial'},
  {_id: 'c', name: 'Platypus', type: 'monotreme'}
]

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':

remote.replicate.to(local, {
  filter: function (doc) {
    return doc.type === 'marsupial';
  }
});

Example 2: Array of doc_ids

Filter documents with _ids ['a', 'c'].

remote.replicate.to(local, {
  doc_ids: ['a', 'c']
});

Example 3: filter function inside of a design document

First put() a design document in the remote database:

{
  _id: '_design/mydesign',
  filters: {
    myfilter: function (doc) {
      return doc.type === 'marsupial';
    }.toString()
  }
}

Then filter by type === 'marsupial':

remote.replicate.to(local, {
  filter: 'mydesign/myfilter'
});

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:

{
  _id: '_design/mydesign',
  filters: {
    myfilter: function (doc, req) {
      return doc.type === req.query.type;
    }.toString()
  }
}

Then filter by type === 'marsupial':

remote.replicate.to(local, {
  filter: 'mydesign/myfilter',
  query_params: {type: 'marsupial'}
});

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:

{
  _id: '_design/mydesign',
  views: {
    myview: function (doc) {
      if (doc.type === 'marsupial') {
        emit(doc._id);
      }
    }.toString()
  }
}

Then filter by type === 'marsupial':

remote.replicate.to(local, {
  filter: '_view',
  view: 'mydesign/myview'
});

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:

db.replicate.to(remote, {
  live: true,
  retry: true,
  back_off_function: function (delay) {
    if (delay === 0) {
      return 1000;
    }
    return delay * 3;
  }
});

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.

Sync a database

var sync = PouchDB.sync(src, target, [options])

Sync data from src to target and target to src. This is a convenience method for bidirectional data replication.

In other words, this code:

PouchDB.replicate('mydb', 'http://localhost:5984/mydb');
PouchDB.replicate('http://localhost:5984/mydb', 'mydb');

is equivalent to this code:

PouchDB.sync('mydb', 'http://localhost:5984/mydb');

Options

Please refer to replicate() for documentation on options, as sync() is just a convenience method that entails bidirectional replication.

Example Usage:

var sync = PouchDB.sync('mydb', 'http://localhost:5984/mydb', {
  live: true,
  retry: true
}).on('change', function (info) {
  // handle change
}).on('paused', function () {
  // replication paused (e.g. user went offline)
}).on('active', function () {
  // replicate resumed (e.g. user went back online)
}).on('denied', function (info) {
  // a document failed to replicate, e.g. due to permissions
}).on('complete', function (info) {
  // handle complete
}).on('error', function (err) {
  // handle error
});

sync.cancel(); // whenever you want to cancel

There is also a shorthand for syncing given existing PouchDB objects. This behaves the same as PouchDB.sync():

db.sync(remoteDB, [options]);

For any further details, please refer to replicate().

Save an attachment

db.putAttachment(docId, attachmentId, [rev], attachment, type, [callback]);

Attaches a binary object to a document.

This method will update an existing document to add the attachment, so it requires a rev if the document already exists. If the document doesn’t already exist, then this method will create an empty document containing the attachment.

What’s the point of attachments? If you’re dealing with large binary data (such as PNGs), you may incur a performance or storage penalty if you naïvely include them as base64- or hex-encoded strings inside your documents. But if you insert the binary data as an attachment, then PouchDB will attempt to store it in the most efficient way possible.

For details, see the CouchDB documentation on attachments.

Example Usage:

Callback:

var attachment = new Blob(['Is there life on Mars?']);
db.putAttachment('doc', 'att.txt', attachment, 'text/plain', function(err, res) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

var attachment = new Blob(['Is there life on Mars?']);
db.putAttachment('doc', 'att.txt', attachment, 'text/plain').then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Example Response:

{
  "ok": true,
  "id": "doc",
  "rev": "2-068E73F5B44FEC987B51354DFC772891"
}

Within Node, you must use a Buffer instead of a Blob:

var attachment = new Buffer('Is there life on Mars?');

For details, see the Mozilla docs on Blob or the Node docs on Buffer.

If you need a shim for older browsers that don’t support the Blob constructor, or you want some convenience methods for Blobs, you can use blob-util.

Save a base64 attachment

If you supply a string instead of a Blob/Buffer, then it will be assumed to be a base64-encoded string, and will be processed accordingly:

Callback:

var attachment = 
        "TGVnZW5kYXJ5IGhlYXJ0cywgdGVhciB1cyBhbGwgYXBhcnQKTWFrZS" +
        "BvdXIgZW1vdGlvbnMgYmxlZWQsIGNyeWluZyBvdXQgaW4gbmVlZA==";
db.putAttachment('doc', 'att.txt', attachment, 'text/plain', function(err, res) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

var attachment = 
        "TGVnZW5kYXJ5IGhlYXJ0cywgdGVhciB1cyBhbGwgYXBhcnQKTWFrZS" +
        "BvdXIgZW1vdGlvbnMgYmxlZWQsIGNyeWluZyBvdXQgaW4gbmVlZA==";
db.putAttachment('doc', 'att.txt', attachment, 'text/plain').then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Save an inline attachment

You can also inline attachments inside the document. The attachment data may be supplied as a base64-encoded string with the content_type:

Callback:

var doc = {
  "_id": "doc",
  "title": "Legendary Hearts",
  "_attachments": {
    "att.txt": {
      "content_type": "text/plain",
      "data": "TGVnZW5kYXJ5IGhlYXJ0cywgdGVhciB1cyBhbGwgYXBhcnQKTWFrZS" +
              "BvdXIgZW1vdGlvbnMgYmxlZWQsIGNyeWluZyBvdXQgaW4gbmVlZA=="
    }
  }
}
db.put(doc, function (err, result) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

var doc = {
  "_id": "doc",
  "title": "Legendary Hearts",
  "_attachments": {
    "att.txt": {
      "content_type": "text/plain",
      "data": "TGVnZW5kYXJ5IGhlYXJ0cywgdGVhciB1cyBhbGwgYXBhcnQKTWFrZS" +
              "BvdXIgZW1vdGlvbnMgYmxlZWQsIGNyeWluZyBvdXQgaW4gbmVlZA=="
    }
  }
}
db.put(doc).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Save an inline Blob/Buffer attachment

You can also inline Blobs/Buffers:

Callback:

var doc = {
  "_id": "doc",
  "title": "Legendary Hearts",
  "_attachments": {
    "_attachments": {
      "att.txt": {
        "content_type": "text/plain",
        "data": new Blob(['Is there life on Mars?'])
      }
    }
  }
}
db.put(doc, function (err, result) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

var doc = {
  "_id": "doc",
  "title": "Legendary Hearts",
  "_attachments": {
    "att.txt": {
      "content_type": "text/plain",
      "data": new Blob(['Is there life on Mars?'])
    }
  }
}
db.put(doc).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Save many attachments at once

The inline approach allows you to save multiple attachments to the same document in a single shot:

Callback:

var doc = {
  "_id": "doc",
  "title": "Legendary Hearts",
  "_attachments": {
    "_attachments": {
      "att.txt": {
        "content_type": "text/plain",
        "data": new Blob(["And she's hooked to the silver screen"])
      },
      "att2.txt": {
        "content_type": "text/plain",
        "data": new Blob(["But the film is a saddening bore"])
      },
      "att3.txt": {
        "content_type": "text/plain",
        "data": new Blob(["For she's lived it ten times or more"])
      }
    }
  }
}
db.put(doc, function (err, result) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

var doc = {
  "_id": "doc",
  "title": "Legendary Hearts",
  "_attachments": {
    "att.txt": {
      "content_type": "text/plain",
      "data": new Blob(["And she's hooked to the silver screen"])
    },
    "att2.txt": {
      "content_type": "text/plain",
      "data": new Blob(["But the film is a saddening bore"])
    },
    "att3.txt": {
      "content_type": "text/plain",
      "data": new Blob(["For she's lived it ten times or more"])
    }
  }
}
db.put(doc).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

See Inline Attachments on the CouchDB wiki for details.

Get an attachment

db.getAttachment(docId, attachmentId, [options], [callback])

Get attachment data.

Example Usage:

Callback:

db.getAttachment('doc', 'att.txt', function(err, res) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

db.getAttachment('doc', 'att.txt').then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Example Response:

The response will be a Blob object in the browser, and a Buffer object in Node.js.

Inline base64 attachments

You can specify {attachments: true} to most “read” operations, such as get(), allDocs(), changes(), and query(). The attachment data will then be included inlined in the resulting doc(s). However, it will always be supplied as base64. For example:

{
  "_attachments": {
    "att.txt": {
      "content_type": "text/plain",
      "digest": "d5ccfd24a8748bed4e2c9a279a2b6089",
      "data": "SXMgdGhlcmUgbGlmZSBvbiBNYXJzPw=="
    }
  },
  "_id": "mydoc",
  "_rev": "1-e147d9ec9c85139dfe7e93bc17148d1a"
}

For such APIs, when you don’t specify {attachments: true}, you will instead get metadata about the attachments. For example:

{
  "_attachments": {
    "att.txt": {
      "content_type": "text/plain",
      "digest": "d5ccfd24a8748bed4e2c9a279a2b6089",
      "stub": true
    }
  },
  "_id": "mydoc",
  "_rev": "1-e147d9ec9c85139dfe7e93bc17148d1a"
}

This “summary” operation may be faster in some cases, because the attachment itself does not need to be read from disk.

Delete an attachment

db.removeAttachment(docId, attachmentId, rev, [callback])

Delete an attachment from a doc. You must supply the rev of the existing doc.

Example Usage:

Callback:

var rev = '1-068E73F5B44FEC987B51354DFC772891';
db.removeAttachment('doc', 'att.txt', rev, function(err, res) {
  if (err) { return console.log(err); }
  // handle result                      
});

Promise:

var rev = '1-068E73F5B44FEC987B51354DFC772891';
db.removeAttachment('doc', 'att.txt', rev).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Example Response:

{
  "ok": true,
  "rev": "2-1F983211AB87EFCCC980974DFC27382F"
}

Query the database

db.query(fun, [options], [callback])

Invoke a map/reduce function, which allows you to perform more complex queries on PouchDB than what you get with allDocs(). The CouchDB documentation for map/reduce applies to PouchDB.

Since views perform a full scan of all documents, this method may be slow, unless you first save your view in a design document. Read the query guide for a good tutorial.

Heads up: eventually the query() API will be deprecated in favor of the much simpler pouchdb-find plugin. You will still be able to use query(), but it will be distributed as a separate plugin.

Options

All options default to false unless otherwise specified.

  • fun: Map/reduce function, which can be one of the following:
    • A full CouchDB-style map/reduce view: {map : ..., reduce: ...}.
    • A map function by itself (no reduce).
    • The name of a view in an existing design document (e.g. 'mydesigndoc/myview', or 'myview' as a shorthand for 'myview/myview').
  • options.reduce: Reduce function, or the string name of a built-in function: '_sum', '_count', or '_stats'. Defaults to false (no reduce).
  • options.include_docs: Include the document in each row in the doc field.
    • options.conflicts: Include conflicts in the _conflicts field of a doc.
    • options.attachments: Include attachment data.
  • options.startkey & options.endkey: Get rows with keys in a certain range (inclusive/inclusive).
  • options.inclusive_end: Include rows having a key equal to the given options.endkey. Default: true.
  • options.limit: Maximum number of rows to return.
  • options.skip: Number of rows to skip before returning (warning: poor performance on IndexedDB/LevelDB!).
  • options.descending: Reverse the order of the output rows.
  • options.key: Only return rows matching this key.
  • options.keys: Array of keys to fetch in a single shot.
    • Neither startkey nor endkey can be specified with this option.
    • The rows are returned in the same order as the supplied keys array.
    • The row for a deleted document will have the revision ID of the deletion, and an extra key "deleted":true in the value property.
    • The row for a nonexistent document will just contain an "error" property with the value "not_found".
  • options.group: True if you want the reduce function to group results by keys, rather than returning a single result. Defaults to false.
  • options.group_level: Number of elements in a key to group by, assuming the keys are arrays. Defaults to the full length of the array.
  • options.stale: One of 'ok' or 'update_after'. Only applies to saved views. Can be one of:
    • unspecified (default): Returns the latest results, waiting for the view to build if necessary.
    • 'ok': Returns results immediately, even if they’re out-of-date.
    • 'update_after': Returns results immediately, but kicks off a build afterwards.

For details, see the CouchDB query options documentation.

Example Usage:

Callback:

// create a design doc
var ddoc = {
  _id: '_design/index',
  views: {
    index: {
      map: function mapFun(doc) {
        if (doc.title) {
          emit(doc.title);
        }
      }.toString()
    }
  }
}

// save the design doc
db.put(ddoc, function (err) {
  if (err && err.status !== 409) {
    return console.log(err);
  }
  // ignore if doc already exists
  // find docs where title === 'Lisa Says'
  db.query('index', {
    key: 'Lisa Says', 
    include_docs: true
  }, function (err, result) {
    if (err) { return console.log(err); }
    // handle result
  });
});

Promise:

// create a design doc
var ddoc = {
  _id: '_design/index',
  views: {
    index: {
      map: function mapFun(doc) {
        if (doc.title) {
          emit(doc.title);
        }
      }.toString()
    }
  }
}

// save the design doc
db.put(ddoc).catch(function (err) {
  if (err.status !== 409) {
    throw err;
  }
  // ignore if doc already exists
}).then(function () {
  // find docs where title === 'Lisa Says'
  return db.query('index', {
    key: 'Lisa Says', 
    include_docs: true
  });
}).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Example Response:

{
  "offset" : 0,
  "rows": [{
    "id": "doc3",
    "key": "Lisa Says",
    "value": null,
    "doc": {
      "_id": "doc3",
      "_rev": "1-z",
      "title": "Lisa Says"
    }
  }],
  "total_rows" : 4
}

In the result,total_rows is the total number of possible results in the view. The response is very similar to that of allDocs().

Note: you can also pass in the map function instead of saving a design doc first, but this is slow because it has to do a full database scan. The following examples will use this pattern for simplicity’s sake, but you should normally avoid it.

Complex keys

You can also use complex keys for fancy ordering:

Callback:

function map(doc) {
  // sort by last name, first name, and age
  emit([doc.lastName, doc.firstName, doc.age]);
}
db.query(map, function (err, response) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

function map(doc) {
  // sort by last name, first name, and age
  emit([doc.lastName, doc.firstName, doc.age]);
}
db.query(map).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Example Response:

{
  "offset": 0,
  "rows": [{
      "id"  : "bowie",
      "key" : ["Bowie", "David", 67]
    }, {
      "id"  : "dylan",
      "key" : ["Dylan", "Bob", 72]
    }, {
      "id"  : "younger_dylan",
      "key" : ["Dylan", "Jakob", 44]
    }, {
      "id"  : "hank_the_third",
      "key" : ["Williams", "Hank", 41]
    }, {
      "id"  : "hank",
      "key" : ["Williams", "Hank", 91]
    }],
  "total_rows": 5
}

Tips:

  • The sort order is [nulls, booleans, numbers, strings, arrays, objects], so {startkey: ['Williams'], endkey: ['Williams', {}]} would return all people with the last name 'Williams' because objects are higher than strings. Something like 'zzzzz' or '\uffff' would also work.
  • group_level can be very helpful when working with complex keys. In the example above, you can use {group_level: 1} to group by last name, or {group_level: 2} to group by last and first name. (Be sure to set {reduce: true, group: true} as well.)

Linked documents

PouchDB fully supports linked documents. Use them to join two types of documents together, by simply adding an _id to the emitted value:

Callback:

function map(doc) {
  // join artist data to albums
  if (doc.type === 'album') {
    emit(doc.name, {_id : doc.artistId, albumYear : doc.year});
  }
}
db.query(map, {include_docs : true}, function (err, response) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

function map(doc) {
  // join artist data to albums
  if (doc.type === 'album') {
    emit(doc.name, {_id : doc.artistId, albumYear : doc.year});
  }
}
db.query(map, {include_docs : true}).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Example response:

{
    "offset": 0,
    "rows": [
        {
            "doc": {
                "_id": "bowie",
                "_rev": "1-fdb234b78904a5c8293f2acf4be70d44",
                "age": 67,
                "firstName": "David",
                "lastName": "Bowie"
            },
            "id": "bowie",
            "key": "Hunky Dory",
            "value": {
                "_id": "album_hunkydory",
                "albumYear": 1971
            }
        },
        {
            "doc": {
                "_id": "bowie",
                "_rev": "1-fdb234b78904a5c8293f2acf4be70d44",
                "age": 67,
                "firstName": "David",
                "lastName": "Bowie"
            },
            "id": "album_low",
            "key": "Low",
            "value": {
                "_id": "bowie",
                "albumYear": 1977
            }
        },
        {
            "doc": {
                "_id": "bowie",
                "_rev": "1-fdb234b78904a5c8293f2acf4be70d44",
                "age": 67,
                "firstName": "David",
                "lastName": "Bowie"
            },
            "id": "album_spaceoddity",
            "key": "Space Oddity",
            "value": {
                "_id": "bowie",
                "albumYear": 1969
            }
        }
    ],
    "total_rows": 3
}

Closures

If you pass a function to db.query and give it the emit function as the second argument, then you can use a closure. (Since PouchDB has to use eval() to bind emit.)

Callback:

// BAD! will throw error
var myId = 'foo';
db.query(function(doc) {
  if (doc._id === myId) {
    emit(doc);
  }
}, function(err, results) {
  // you'll get an error here
});

// will be fine
var myId = 'foo';
db.query(function(doc, emit) {
  if (doc._id === myId) {
    emit(doc);
  }
}, function(err, results) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

// BAD! will throw error
var myId = 'foo';
db.query(function(doc) {
  if (doc._id === myId) {
    emit(doc);
  }
}).catch(function (err) {
  // you'll get an error here
}

// will be fine
var myId = 'foo';
db.query(function(doc, emit) {
  if (doc._id === myId) {
    emit(doc);
  }
}).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Note that closures are only supported by local databases with temporary views. So if you are using closures, then you must use the slower method that requires a full database scan.

View cleanup

db.viewCleanup([callback])

Cleans up any stale map/reduce indexes.

As design docs are deleted or modified, their associated index files (in CouchDB) or companion databases (in local PouchDBs) continue to take up space on disk. viewCleanup() removes these unnecessary index files.

See the CouchDB documentation on view cleanup for details.

Example Usage:

Callback:

db.viewCleanup(function (err, result) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

db.viewCleanup().then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Example Response:

{ "ok" : "true" }

Get database information

db.info([callback])

Get information about a database.

Example Usage:

Callback:

db.info(function(err, info) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

db.info().then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Example Response:

{
  "db_name": "test",
  "doc_count": 4,
  "update_seq": 5
}

Response object:

  • db_name is the name of the database you gave when you called new PouchDB(), and also the unique identifier for the database.
  • doc_count is the total number of non-deleted documents in the database.
  • update_seq is the sequence number of the database. It starts at 0 and gets incremented every time a document is added or modified.

There are also some details you can use for debugging. These are unofficial and may change at any time:

  • idb_attachment_format: (IndexedDB) either 'base64' or 'binary', depending on whether the browser supports binary blobs.
  • sqlite_plugin: (WebSQL) true if the SQLite Plugin is being used.
  • websql_encoding: (WebSQL) either 'UTF-8' or 'UTF-16', depending on the WebSQL implementation

Compact the database

db.compact([options], [callback])

Triggers a compaction operation in the local or remote database. This reduces the database’s size by removing unused and old data, namely non-leaf revisions and attachments that are no longer referenced by those revisions. Note that this is a separate operation from viewCleanup().

For remote databases, PouchDB checks the compaction status at regular intervals and fires the callback (or resolves the promise) upon completion. Consult the compaction section of CouchDB’s maintenance documentation for more details.

Also see auto-compaction, which runs compaction automatically (local databases only).

  • options.interval: Number of milliseconds to wait before asking again if compaction is already done. Defaults to 200. (Only applies to remote databases.)

Example Usage:

Callback:

db.compact(function (err, result) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

db.compact().then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Example Response:

{ "ok" : "true" }

Document revisions diff

db.revsDiff(diff, [callback])

Given a set of document/revision IDs, returns the subset of those that do not correspond to revisions stored in the database. Primarily used in replication.

Example Usage:

Callback:

db.revsDiff({
  myDoc1: [
    "1-b2e54331db828310f3c772d6e042ac9c",
    "2-3a24009a9525bde9e4bfa8a99046b00d"
  ]
}, function (err, result) {
  if (err) { return console.log(err); }
  // handle result
});

Promise:

db.revsDiff({
  myDoc1: [
    "1-b2e54331db828310f3c772d6e042ac9c",
    "2-3a24009a9525bde9e4bfa8a99046b00d"
  ]
}).then(function (result) {
  // handle result
}).catch(function (err) {
  console.log(err);
});

Example Response:

{
  "myDoc1": {
    "missing": ["2-3a24009a9525bde9e4bfa8a99046b00d"]
  }
}

Events

PouchDB is an event emitter and will emit a 'created' event when a database is created. A 'destroyed' event is emitted when a database is destroyed.

PouchDB.on('created', function (dbName) {
  // called whenver a db is created.
});
PouchDB.on('destroyed', function (dbName) {
  // called whenver a db is destroyed.
});

Default settings

If you find yourself using the same constructor options repeatedly, you can simplify your code with PouchDB.defaults():

PouchDB.defaults({
  option1: 'foo',
  option2: 'value'
});

The returned object is a constructor function that works the same as PouchDB, except that whenever you invoke it (e.g. with new), the given options will be passed in by default.

Example Usage:

var MyMemPouch = PouchDB.defaults({
  db: require('memdown')
});
// MemDOWN-backed Pouch (in Node)
var MyMemPouch = new MyMemPouch('dbname');

var MyPrefixedPouch = PouchDB.defaults({
  prefix: '/path/to/my/db/'
});
// db will be named '/path/to/my/db/dbname', useful for LevelDB
var myPrefixedPouch = new MyPrefixedPouch('dbname');

Note the special constructor option prefix, which appends a prefix to the database name and can be helpful for URL-based or file-based LevelDOWN path names.

All constructor options are supported. Default options can still be overriden individually.

Plugins

Writing a plugin is easy! The API is:

PouchDB.plugin({
  methodName: myFunction
});

This will add a db.methodName() to all databases, which runs myFunction.It will always be called in context, so that within the function, this refers to the database object.

There is a PouchDB Plugin Seed project, which is the fastest way to get started writing, building and testing your very own plugin.

Example Usage:

PouchDB.plugin({
  sayHello : function () {
    console.log("Hello!");
  }
});
new PouchDB('foobar').sayHello(); // prints "Hello!"

Extras

PouchDB offers some “extra” APIs that are designed for PouchDB plugin authors, or for those who want to use non-standard adapters like in-memory and LocalStorage.

These can be especially useful when you are using Browserify/Webpack, because they can reduce your overall code size by deduplicating packages. If you’re not using Browserify/Webpack, you can also download them as standalone scripts.

Browser adapter plugins

These adapters are alternatives to PouchDB’s built-in IndexedDB/WebSQL adapters. They fully pass the PouchDB test suite.

LocalStorage adapter

var PouchDB = require('pouchdb');
require('pouchdb/extras/localstorage');

var db = new PouchDB('mydb', {adapter: 'localstorage'});

PouchDB adapter using LocalStorage. Intended for browsers and environments that don’t support IndexedDB or WebSQL. Based on localstorage-down.

You can also download this plugin as a standalone script.

In-memory adapter

var PouchDB = require('pouchdb');
require('pouchdb/extras/memory');

var db = new PouchDB('mydb', {adapter: 'memory'});

Fully in-memory PouchDB adapter. Data will not be saved after a browser refresh!

This adapter can be useful for unit tests or for environments that don’t support IndexedDB/WebSQL. Based on MemDOWN.

You can also download this plugin as a standalone script.

If you want to use an in-memory PouchDB in Node.js/io.js, you should directly require MemDOWN instead.

Alternative IndexedDB adapter

var PouchDB = require('pouchdb');
require('pouchdb/extras/idb-alt');

var db = new PouchDB('mydb', {adapter: 'idb-alt'});

PouchDB adapter using level-js over IndexedDB as a storage backend. Mostly only interesting to PouchDB developers; someday, this may replace the standard IndexedDB adapter.

You can also download this plugin as a standalone script.

When you include these plugins in your project, they will be automatically picked up as a “third” option when you create a new PouchDB without an adapter specified (e.g. new PouchDB('mydb')).

So for instance, if the user loads PouchDB in a browser that does not support WebSQL or IndexedDB, and if you are using the in-memory plugin, then PouchDB will automatically use the memory adapter instead of WebSQL or IndexedDB.

APIs for plugin authors

These APIs are designed for PouchDB plugin authors, who may want to re-use some PouchDB code to avoid duplication.

To use these APIs, you should save PouchDB as a required npm dependency (npm install --save pouchdb) and then require them like so:

Ajax

var ajax = require('pouchdb/extras/ajax');

The ajax() function as used by PouchDB. Essentially a shim in the style of jQuery.ajax.

Checkpointer

var Checkpointer = require('pouchdb/extras/checkpointer');

The Checkpointer function as used by PouchDB’s replicator. Writes checkpoints as _local docs so that replication can resume where it last left off.

Promise

var Promise = require('pouchdb/extras/promise');

The ES6 Promise shim as used by PouchDB. Expect this to be bluebird in Node, lie in browsers without Promise support, and the global Promise in browsers with Promise support.

Caveats

These APIs are not rigorously documented and may change frequently. Refer to the source code for the details of the APIs.

If your plugin depends on a particular version of PouchDB, please notify your users. Unless you like to live dangerously, you should also nail down the version of PouchDB you are using in your package.json. And if you need any other internal modules, please submit a pull request!

Debug mode

PouchDB uses the debug module for fine-grained debug output.

To enable debug mode, just call:

PouchDB.debug.enable('*');

In your browser console, you should then see something like this:

Coloured Log Output

In Node.js, you can also set a command-line flag:

DEBUG=pouchdb:* node myscript.js

You can also enable debugging of specific modules. Currently we only have pouchb:api (API-level calls) and pouchdb:http (HTTP requests):

PouchDB.debug.enable('pouchdb:api'); // or
PouchDB.debug.enable('pouchdb:http');

These settings are saved to the browser’s LocalStorage. So to disable them, you must call:

PouchDB.debug.disable();

Your users won’t see debug output unless you explicitly call PouchDB.debug.enable() within your application code.