CouchDB library with a simple, functional-programing-friendly API.
Forked from Cot, and renamed blue-cot
in reference to the Bluebird promises it was returning until v4.0.0
.
Summary
Installing
npm install blue-cot
Specificities of this lib
Especially compared to Cot from which it is forked
- Class-less, thus a different initialization, but the rest of the API stays the same
- Consequently,
blue-cot
is this
-free: no need to bind functions contexts! 4xx
and 5xx
responses will return rejected promises (should be handled with .catch
)- Adds a few new functions, notably some view functions goodies
- Uses Cookie Authentication instead of Basic Auth for better performance
- Uses a single persistent connexion to CouchDB by default
Initialization
const bluecot = require('blue-cot')
const config = {
protocol: 'http',
hostname: 'localhost',
port: 5984,
username: 'your-couchdb-username',
password: 'your-couchdb-password',
debug: true,
agent: myAgent
}
const getDbApi = bluecot(config)
const db = getDbApi('some-db-name')
with Bluebird
From v4.0.0
, blue-cot
stopped returning Bluebird promises, but if you miss that feature, you can recover it by initializing bluebird
before blue-cot
:
global.Promise = require('bluebird')
const bluecot = require('blue-cot')
const getDbApi = bluecot(config)
const db = getDbApi('some-db-name')
API
Database functions
To handle database and design documents creation, see couch-init2
info
GET /<dbName>
const data = await db.info()
Documents functions
get
GET /<dbName>/<docId>
Takes a document id and optionaly a rev id to get a specific version:
const latestDocVersion = await db.get('doc-1')
const specificVersion = await db.get('doc-1', '2-b8476e8877ff5707de9e62e70a8e0aeb')
Missing documents are treated as an error, and thus return a rejected promise.
post
POST /<dbName>
const res = await db.post(doc)
Creates a new document or updates an existing document. If doc._id
is undefined, CouchDB will generate a new ID for you.
On 201, returns result from CouchDB which looks like: {"ok":true, "id":"<docId>", "rev":"<docRev>"}
All other status codes (including 409, conflict) are treated as errors, and thus return a rejected promise.
put
PUT /<dbName>/<doc._id>
const res = await db.put(doc)
On 409 (conflict) returns result from CouchDB which looks like: {"error":"conflict"}
On 201, returns result from CouchDB which looks like: {"ok":true, "id":"<docId>", "rev":"<docRev>"}
All other status codes are treated as errors, and thus return a rejected promise.
delete
DELETE /<dbName>/<docId>?rev=<rev>
const res = await db.delete(docId, rev)
On 200, returns result from CouchDB which looks like: {"ok":true, "id":"<docId>", "rev":"<docRev>"}
All other status codes are treated as errors, and thus return a rejected promise.
If you wish to gracefully handle update conflicts while deleting, use db.put()
on a document with _deleted
set to true
:
doc._deleted = true
const res = await db.put(doc)
if (!res.ok) {
}
find
POST /<dbName>/_find_
(endpoint available in CouchDB >= 2.0
)
Takes a _find
query object
const { docs, bookmark } = await db.find({
selector: {
year: { $gt: 2010 }
},
fields: [ '_id', '_rev', 'year', 'title' ],
sort: [ { year: 'asc' } ],
limit: 2,
skip: 0,
use_index: [ 'some_design_doc_name', 'some_index_name' ],
execution_stats: true
})
By default, this function will throw if receiving a warning; this behavior can be disable by passing strict=false
:
const query = {
selector: {
year: { $gt: 2010 }
}
}
const { docs, bookmark, warning } = await db.find(query, { strict: false })
To send the same query to the _explain
endpoint instead, use the explain
flag:
const query = {
selector: { name: 'foo' }
}
const { docs, bookmark, warning } = await db.find(query, { explain: true )
postIndex
POST /<dbName>/_index
const { result } = await db.postIndex({
index: {
fields: [ 'type' ]
},
ddoc: 'some_ddoc_name',
name: 'by_type'
})
exists
GET /<dbName>/<docId>
const res = await db.exists(docId)
Returns a promise resolving to true if it exist, or a rejected promise if it doesn't.
batch
POST /<dbName>?batch=ok
const res = await db.batch(doc)
doc: Batch Mode
Creates or updates a document but doesn't wait for success. Conflicts will not be detected.
On 202, returns result from CouchDB which looks like: {"ok":true, "id":"<docId>"}
The rev isn't returned because CouchDB returns before checking for conflicts. If there is a conflict, the update will be silently lost.
All other status codes are treated as errors, and thus return a rejected promise.
update
const res = await db.update(docId, updateFunction)
Gets the specified document, passes it to updateFunction
, and then saves the results of updateFunction
over the document
The process loops if there is an update conflict.
By default, db.update
only accepts to update existing docs, but this can be changed by setting createIfMissing=true
:
const res = await db.update(docId, updateFunction, { createIfMissing: true })
bulk
POST /<dbName>/_bulk_docs
const res = await db.bulk(docs)
See CouchDB documentation for more information
allDocs
GET /<dbName>/_all_docs?<properly encoded query>
const { rows } = await db.allDocs(query)
Queries the _all_docs
view. query
supports the same keys as in db.view
.
allDocsKeys
Loads documents with the specified keys and query parameters
const { rows } = await db.allDocsKeys(keys, query)
Couchdb documentation
fetch
Takes doc ids, returns docs.
const { docs, errors } = await db.fetch([ 'doc-1', 'doc-2', 'doc-3', 'some-non-existing-doc' ])
docs[0]._id === 'doc-1'
docs[1]._id === 'doc-2'
docs[2]._id === 'doc-3'
errors[0].key === 'some-non-existing-doc'
errors[0].error === 'not_found'
changes
Queries the changes feed given the specified query. query
may contain the following keys:
filter
: filter function to useinclude_docs
: if true, results will contain entire documentlimit
: the maximum number of change rows this query should returnsince
: results will start immediately after the sequence number provided herelongpoll
: if true, query will send feed=longpolltimeout
: timeout in milliseconds for logpoll queries
See CouchDB changes feed documentation
listRevs
Takes a doc id, returns the doc's rev infos
const revsInfo = await db.listRevs('doc-1')
revsInfo
will look something like:
[
{ rev: '3-6a8869bc7fff815987ff9b7fda3e10e3', status: 'available' },
{ rev: '2-88476e8877ff5707de9e62e70a8e0aeb', status: 'available' },
{ rev: '1-a8bdf0ef0b7049d35c781210723b9ff9', status: 'available' }
]
revertLastChange
Takes a doc id and reverts its last change, recovering the previous version.
Only works if there is a previous version and if it is still available in the database (that is, if it wasn't deleted by a database compaction).
It doesn't delete the last version, it simply creates a new version that is exactly like the version before the current one.
const res = await db.revertLastChange('doc-1')
revertToLastVersionWhere
Takes a doc id and a function, and reverts to the last version returning a truthy result when passed through this function.
Same warnings apply as for revertLastChange
.
const desiredVersionTestFunction = doc => doc.foo === 2
db.revertToLastVersionWhere('doc-1', desiredVersionTestFunction)
undelete
Mistakes happen
await db.delete(docId, docRev)
await db.undelete(docId))
const restoredDoc = await db.get(docId))
:warning: this will obviously not work if the version before deletion isn't in the database (because the database was compressed or it's a freshly replicated database), or if the database was purged from deleted documents.
View functions
view
GET /<dbName>/_desgin/<designName>/_view/<viewName>?<properly encoded query>
const { rows, total_rows, offset } = db.view(designName, viewName, query)
Queries a view with the given name in the given design doc. query
should be an object with any of the following keys:
- descending
- endkey
- endkey_docid
- group
- group_level
- include_docs
- inclusive_end
- key
- limit
- reduce
- skip
- stale
- startkey
- startkey_docid
- update_seq
For more information, refer to Couchdb documentation
viewQuery
viewKeysQuery
viewKeys
Design doc specific view functions
Those functions are pre-filled versions of the view functions above for the most common operations, like to get all the documents associated to an array of ids.
To access those, pass a design doc name as second argument
const db = getDbApi('some-db-name', 'some-design-doc-name')
viewCustom
viewByKeysCustom
viewByKey
viewFindOneByKey
viewByKeys
see lib/view_functions
If you find this module useful, consider making a PR to improve the documentation
Utils
buildQueryString
See also
you might want to consider using couchdb-nano, the now offical (but bloated ;p) CouchDB NodeJS lib