A few months back, I was talking with some of the users of our Node.js client and heard a fairly standard opinion that people were looking for some method to simplify their life further when using Couchbase from Node.js.  One particular things that I heard a lot about was they were looking for some way to have automatically generated models to avoid needing to manually build up all the boilerplate themselves.

In response to this, I started working on a new library known as Ottoman.  Ottoman is an experimental ODM designed around Couchbase.   At this point I feel that Ottoman is sufficiently feature rich to begin having some external eyes taking a look.  I know that there are bugs hiding out in the source, and features that could be enhanced but I'd like your help to do it!  You're the one with the best idea of what you want to see and what would be most beneficial to YOU, so I want to hear from you with as many of the questions, comments and/or concerns you might have.

Onwards with some explanations! 

The library is meant to allow you to build a definition of what your model would look like, and then have it auto-generate all the boilerplate that usually goes with this.  As an example, take a look at the following:

var User = Ottoman.model(‘User’, {
  ‘username’: ‘string’,
  ‘name’: ‘string’,
  ’email’: ‘string’
}, {
  bucket: new couchbase.Connection({})
});

This example shows how to create a simple User model, which contains 5 fields (yes 5, I will explain this below).  It intuitively contains a 3 string fields, which are username, name and email.  Additionally, there are 2 hidden fields which are added on and which can be overridden.  These fields are the _type and _id fields, which contain a string of what model this document is, as well as a uniquely identifying string, which defaults to using a UUIDv4 uuid.

Using this newly created model is extremely simple as the return object from the model function is a function that can be used to instantiate new instances of the model.  So following the example above, we can create and save a new user with the following:

var test = new User();
test.username = ‘brett19’;
test.name = ‘Brett Lawson’;
test.email = ‘brett19@gmail.com’;

Ottoman.save(test, function(err) {
  if (err) throw err;
  console.log(‘saved’);
});

Ottoman additionally allows you to quickly load an object that was previously stored to the database by using findById as well, such as this:

User.findById(test._id, function(err, obj) {
  if (err) throw err;

  console.log(obj.name);
  // Brett Lawson
});

So far, we have essentially just looked at some simple load/store operations that Ottoman can do, lets get a bit deeper than that and see where Ottoman can really help increase our productivity.  Lets now say that we are building a blog site, and we need to store a blog post associated to users.  Lets build a model to let us do this.

var BlogPost = Ottoman.model(‘User’, {
  ‘creator’: ‘User’,
  ‘title’: ‘string’,
  ‘content’: ‘string’
}, {
  bucket:
});

You can see here that one of our field types actually refers to our User object created above.  This allows us to create a new BlogPost that refers to another document stored in our database.  You can also configure a model to be embedded.  Lets say we wanted to store the current GPS location of the user, as well as their GPS location when they make a post.  We could define a model like this, and use it from User and BlogPost, rather than being a normal referenced document, the data will be directly embedded in their respective objects, but remain as GPSPosition's when de-serialized.

var GPSPosition = Ottoman.model(‘GPSPosition’, {
  lat: ‘number’,
  long: ‘number’
}, {
  embed: true
});

The last interesting feature I would like to mention today is the ability to automatically generate map/reduce views that allow you to preform basic lookups for our models.  I would like to strongly prefix this by saying this feature is very much experimental and only works for some of the most common use cases.  Additionally it has the caveat of needing you go manually call registerDesignDocs on the Ottoman object after all your models have been registered as this is the only way to determine model linkages, additionally, regenerating these views on every startup of your app would be horribly inefficient, so I usually do it as a sort of setup phase at the moment.

To take our blog example even further, lets say we needed a list of our user's blog posts.  Normally this would involve manually building a view to extract this list by searching all BlogPost's on the creator reference for the specific user we are looking for.   With Ottoman this is much simpler.   We can simply define a query in the properties for our User object like so:

      queries: {
        myPosts: {
          target: ‘BlogPost’,
          mappedBy: ‘creator’,
          sort: ‘desc’,
          limit: 5
        }
      },

Now you can request the posts made by a user simply by invoking the myPosts method on any User instance and you will be returned a list of BlogPost objects that were posted by this user, the location and deserialization of these objects is handled automatically.

There are a ton more features supported by Ottoman that I don't have time to show off today, but if you want to see more or want to help out make Ottoman even better, head on over to the GitHub page here: https://github.com/couchbaselabs/node-ottoman/ !

Cheers! Brett

Author

Posted by Brett Lawson, Principal Software Engineer, Couchbase

Brett Lawson is a Principal Software Engineer at Couchbase. Brett is responsible for the design and development of the Couchbase Node.js and PHP clients as well as playing a role in the design and development of the C library, libcouchbase.

14 Comments

  1. Brett,

    I spent time search for an objet model for Couch and came across the NPM and now your blog post.

    You [and the other Node.js users] are bang on that this is sorely needed.

    I hate to say it, but Mongoose seems to have it right with schemas already in terms of ease of use and this gets us a bit closer in the Couch world. Not saying that Mongoose has everything right, though ;)

    The completely transparent/hidden ID and type is also the way to go, IMHO (one up on Mongoose here :)

    I\’ll fork the Github and have a play.

    Cheers,

    -m

    1. Hey Marc,
      Let me know if you have any questions about the source, or Ottoman in general. There are a lot of features that I\’m still working on documenting, additionally, the source code should be pretty sane to browse through except the querying code which is still being prototyped.
      Cheers, Brett

  2. good job! right direction! I started to work on a sailsjs-adapter (http://sailsjs.org/#!documenta…. Will check out ottoman and your concepts

  3. Hi Brett,

    thanks for this work and I fully agree with @disqus_gkZwtATXIN:disqus here that there is a gap to Mongoose that would be great if we could close it with Ottoman. I\’m reading \”Sams teach yourself Node.js in 24 hours\” and they use Mongoose heavily in their example section thus making me envy about MongoDB user who have an easy way with all.

    Having said that, and please pardon me as a learner of Node.js and Noob,as I\’m much in testing my first app on Node.js I\’m currently at a step where I\’m adding data from various sources and would like to see a function in Ottoman that is deleting only a specific schema (or in Ottoman\’s language a model) with one simple command.

    Not sure if that is understood but what I want is a clean slate as I\’m testing how to handle multiple entries with the same ID and having the data currently inside from the last run will throw an error on every record (not only on those that are really duplicates).

    The Node.js community on CouchBase is still very small is seems but as we can see with the Viber case there are more and more companies who see \”the light\” and switch over.

    Thanks for your work on this, @brettlawson:disqus!

    1. Hey Andreas,
      I appreciate you taking the time to disseminate your thoughts here! I agree that there are some things that are more challenging to complete with Couchbase, and we are working hard to try and bridge that gap for developers. Unfortunately it is non-trivial to delete all the data for a particular subset of your data at the moment (though we could build a view to allow us to do this). However, for your use-case, might I suggest using the database\’s \’flush\’ command, which will completely eradicate the data in a particular bucket, or better yet, in the case of running tests, perhaps using the Node.js\’s mock may be a better solution, it is powerful tool to use for testing and is much faster than using a real cluster!
      Cheers, Brett

      1. Thanks for your help @brettlawson:disqus and I implemented the FLUSH already. I\’ve looked up Node.js mock and there are many different ones. As usual it\’s hard to identify \”the best\” solution, anyone which you prefer over the others when it comes to \”mocking\” around?

  4. Hi Brett,
    Great start here. In my eyes – ODM is really the missing link in the Couch/Node Stack and Mongoose is quickly making Couch-use VS Mongo-use a less & less attractive option.

    How likely is this project to get to the feature / robustness level of Mongoose? Is this a back-burner project or front-burner project at CB?

    Thanks! CM

    1. Hey CM!
      Ottoman is actually already extremely feature full, but most of these features have not been documented as of yet. This is indeed a front-burner project, but we are currently in the process of major refactoring of our base clients and thus development has been slow, additionally, we have yet to have a significant number of people show interest in the project. Do you have any thoughts on the project?
      Cheers, Brett

  5. As I am new to Couchbase I\’ve been making some mistakes while trying to
    migrate a system from MongoDB to Couchbase, particularly with regards to
    the design of views/indexes. I hope someone can help.

  6. I just stumbled upon this page from the couchbase training app. Makes sense to add ottoman. Similar lines as ORM tools in relational world – almost every nosql db should be needing it – http://www.fromdev.com/2012/07

    What about your plans on cross nosql compatibility? Or is it going to be specific to couchbase only.

  7. Esteban Echeverry Perez August 29, 2015 at 9:16 pm

    Is Ottoman still maintained? If not, which would be the best ODM for Couchbase in NodeJS?

    1. Here is another couchbase odm you can try:
      https://github.com/fogine/couc

  8. Gaurav Bansal May 10, 2016 at 5:09 am

    Hi Brett,

    I am new to Couch Base and Ottoman, the reason to move to couch base was the views they support. I did read in blogs that Ottoman supports interaction with views in Couch base via API but was not able to find the same can you help me by directing me to some documentation where in I can read and explore the API support for View interaction in Ottoman.

    thanks

    Gaurav

  9. […] Blog of the Week: Node.js ODM for Couchbase (Ottoman) […]

Leave a reply