Question

I am using Cradle to store objects in CouchDB from my Node.js server. The objects contain functions....

function AnObject(a, b){
this.a = a; this.b = b;
this.addparts = function(){return this.a + this.b;};}

var cradle = require('cradle');
var db = new(cradle.Connection)('http://localhost', 5984, {cache: true, raw: false}).database('myDB');

var myObject = new AnObject(1, 2);
console.log("addparts:" + myObject.addparts());
db.save('myObjectId', myObject);

This works fine and the document is stored but when I retrieve it, I can no longer call the function on the returned document...

db.get('myObjectId', function(err, myRetrievedObject){
console.log("addparts:" + myRetrievedObject.addparts());
});

This fails with a (Property is not a function) Error..

node cradle_test

cradle_test.js:21
console.log("addparts:" + myRetrievedObject.addparts());
                                         ^
TypeError: Property 'addparts' of object {"_id":"myObjectId","_rev":"2-83535db5101fedfe30a1548fa2641f29","a":1,"b":2,"addparts":"function (){return this.a + this.b;}"} is not a function
Was it helpful?

Solution

CouchDB stores JSON. Functions are not valid JSON. Functions are never stored in the database.

I recommend you move the functions out into a prototype.

function AnObject(a, b){
    this.a = a; this.b = b;
}

AnObject.prototype.addparts = function(){
    return this.a + this.b;
};

db.get('myObjectId', function(err, myRetrievedObject){
    var obj = Object.create(AnObject.prototype);
    // for some value of extend ( https://github.com/Raynos/pd#pd.extend )
    extend(obj, myRetrievedObject);
    console.log("addparts:" + obj.addparts());
});

This way your not saving functions and you can still operate on your object using your methods. You just have to make sure that your retrieved object is made an instance of AnObject

OTHER TIPS

There is a way to store functions in CouchDB: as attachments.

Define your functions in a separate .js file (for example, a set of functions you want to share across multiple servers or app instances).

/modules/db.js:

var db = {}

db.insert = function(nanoDb, object, cb){
  //insert new doc
  nanoDb.insert(object, function(err, body, header) {
    if (!err) {
      cb.call(null, {success: true, data: body});

    }else{
      console.log('[insert] ', err.message); 
      cb.call(null, {success: false, error: err.message});
    }
  });
}

db.bulkInsert = function(nanoDb, array, cb){
  //structure for bulk insert
  var data = {
    docs: array
  }
  //insert new doc
  nanoDb.bulk(data, function(err, body, header) {
    if (!err) {
      cb.call(null, {success: true, data: body});

    }else{
      console.log('[bulkInsert] ', err.message); 
      cb.call(null, {success: false, error: err.message});
    }
  });
}

db.bulkDelete = function(nanoDb, array, cb){
  for(i in array){
    array[i]._deleted = true;
  }
  var data = {
    docs: array
  }
  //check if the url exists in the db
  nanoDb.bulk(data, function(err, body) {
    if (!err){  
      cb.call(null, {success: true, data: data});
    }else{
      console.log('[bulkDelete] ', err.message);
      cb.call(null, {success: false, error: err.message});
    }
  });
}

db.view = function(nanoDb, design, view, params, cb){
  nanoDb.view(design, view, params, function(err, body) {
    if (!err){
      var docs = util.extractDocs(body);
      cb.call(null, {success: true, data: docs});
    }else{
      console.log('[view] ', err.message);
      cb.call(null, {success: false, error: err.message});
    }
  });
}

db.search = function(nanoDb, design, index, params, cb){
  nanoDb.search(design, index, params, function(err, body) {
    if (!err) {
      var docs = util.extractDocsSearch(body);
      cb.call(null, {success: true, data: docs});
    }else{
      console.log('[search] ', err.message);
      cb.call(null, {success: false, error: err.message});
    }
  }); 
}

db.follow = function(nanoDb, params){
  var feed = nanoDb.follow(params);
  return feed;
}

module.exports = db;

Use a CouchApp to deploy the functions as attachments (in a design doc):

//your couchapp
var couchapp = require('couchapp')

//url to your database
var url = '...';

//empty design doc (for attachments)
ddoc = {
  _id: '_design/mods'
};

//folder containing .js files
couchapp.loadAttachments(ddoc, './modules/');

//this function uploads your attachments
couchapp.createApp(ddoc, url, function(app) {
  app.push(function(){
    //do something
  });
});

Now, get the functions wherever you need them:

//use mikaels request module if you like
var request = require('request');

//tell the app where to get your .js file
//sometimes a good idea to persist these references in memory or even in your couchdb
var fileUrl = '/_design/modules/db.js'

//set this variable in the proper scope
var db;

//we'll use this to 'require' the .js file
var _require = function(src, file) {
  var m = new module.constructor();
  m.paths = module.paths;
  m._compile(src, file);
  return m.exports;
}

request({ url: fileUrl, json: true }, function (err, response, data) {
  if (!err && response.statusCode === 200) {
    //now we assign our required .js file (object w/functions) back into usable form
    //woot woot!
    db = _require(data);
  }else{
    console.log('[request]', err);
  }
});

Do stuff!

db.doSomething()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top