New Power Manual


    1.0.0 • Public • Published


    Build Status Dependency Status Coverage Status

    Working with CouchDB is a pretty pleasant experience, mostly because of the rather excellent nano library.

    There are a couple of rough edges though, so what else could be better but an abstracton on top of an abstraction!


    Create me a repository:

    var Nano = require('nano'),
      Repository = require('nano-repository');
    // set up Nano
    var connection = new Nano('http://localhost:5984');
    var db = connection.db.create('my_db');
    // set up repo
    var repository = new Repository(db);

    CRUD operations

    var document = {foo: 'bar'};
    // create, function(error, result) {
        // document now has _id, _rev and created_at properties
    // retrieve
    repository.findById(id, function(error, document) {
        // document has been fetched
    // update, function(error, result) {
        // if previously saved, document now has updated_at properties
        // and _rev has been incremented
    // delete
    repository.remove(document, function(error) {
        // document has been deleted


    Add files to your documents:

    repository.addAttachment(document, attachmentName, pathToFile, mimeType, function(error, body) {
      // file has now been attached

    Retrieve attachments:

    repository.findAttachment(document, name, function(error, body) {
      // body contains the attachment data

    Attachment versions

    The attachment version is dependent on the document version. E.g if you will pardon the pyramid of doom:

    var attachmentName = 'myFile';
    // add the first version of the attachment
    repository.addAttachment(document, attachmentName, pathToFile, mimeType, function(error, body) {
      // now document._rev = 2
      // add the second it again:
      repository.addAttachment(document, attachmentName, pathToFile, mimeType, function(error, body) {
        // now document._rev = 3
        // we now have two revisions of 'myFile' that we can access:
        repository.findAttachment({_id: document._id, _rev: 2}, attachmentName, function(error, body) {
          // body contains the first version of myFile
        repository.findAttachment({_id: document._id, _rev: 3}, attachmentName, function(error, body) {
          // body contains the second version

    Streaming attachments

    For the performance/memory conscious, stream files to your documents with the 4x argument version of Repository.addAttachment:

    var fileStream = fs.createReadStream(pathToFile);
    fileStream.pipe(repository.addAttachment(document, attachmentName, mimeType, function(error, body) {
      // file has now been attached

    ...and retrieve them:

    repository.streamAttachmentTo(document, name, writeStream);


    Views are accessed by extra methods on the Repository. To create your views, first create a view template file, usally with the .json extension.

    The template file looks like this (n.b. feel free to include reduce functions if you need them):

      "views": {
        "all": {
          "map": "function(doc) {if( emit(null, doc)}"
        "byName": {
          "map": "function(doc) {if( emit(, doc)}"

    Update/create the views:

    var repository = new Repository(db);
    repository.updateViews('path/to/views.json', function(error) {
      // views are now ready to use

    View methods are dynamically created:

    repository.findAll(function(error, list) {
      // list contains all documents from this collection

    Method names are chosen by capitalising the first letter of the view name and prepending find to it.

    So the view mapping file contained a view named all - this was turned into findAll, similarly the view named byName was turned into a method named findByName.

    Arguments are also supported:

    repository.findByName('bob', function(error, list) {
      // list contains all documents where == 'bob'

    The code that makes up your view is hashed - the hash is stored along with the views. The next time you call Repository.updateViews the hashes are compared - it they've changed then the views are recreated automatically.

    This means it's save to call Repository.updateViews every time you start your app - they'll only get altered if you change the code in your view file.

    Get out of my console.log

    You can pass an alternative logging implementation into the constructor and the repository will use that instead, as long as it supports .info, .warn, etc methods.

    var Nano = require('nano'),
      Logger = require('winston').Logger,
      logger = new Logger(..);
    //.. set up Nano as usual
    var repository = new Repository(db, logger);


    1. Retrieving specific document versions.
    2. Work out if I've missed the point somehow. Probably.




    npm i nano-repository

    DownloadsWeekly Downloads






    Last publish


    • achingbrain