JavaScript
Article
By Aldo Ziflaj

3 JavaScript ORMs You Might Not Know

By Aldo Ziflaj

When I wrote my first JavaScript lines, I never thought it would go beyond browser scripting and making interactive websites. I was wrong since JavaScript can be used literally everywhere:

  • You can use it in the browser and you don’t have to be restricted to ECMAscript with DOM API. Languages like CoffeeScript and Dart, transpilable to plain old JavaScript, can help you develop faster and better code.
  • You can use it on the server. Node.js and plenty of its frameworks are increasing in number and helping front-end developers become full-stack developers.
  • You can use it for mobile apps. Using Cordova and frameworks like Ionic or NativeScript, you can build mobile apps faster without the need to know other languages like Java or Swift/Objective-C. Thanks to these frameworks, you can even share the source code between mobile platforms.
  • You can build IoT. SitePoint has published some articles by Patrick Catanzariti which can be very helpful for this purpose.

With an increased complexity of the application you’re developing, you would need something to help you deal with all the data you’re storing in the database, whether in a DB server (like PostgreSQL), in the embedded SQLite of mobile devices, or in the browser. Here comes the need for ORMs. The Java community has Hibernate, the PHP developers can use Doctrine ORM, and the JavaScript community has its own ORMs.

In this article, I’ll give you an introduction of some JavaScript ORMs which can help you deal with complex data in your next application.

Bookshelf.js

Bookshelf.js is an ORM for Node.js, designed to work well with PostgreSQL, MySQL, MariaDB and SQLite3. It is build on top of Knex SQL query builder and follows some patterns seen in Backbone.js, such as models and collections and similar naming conventions. If you have ever used Backbone, you’ll probably adapt Bookshelf really fast.

To install Bookshelf, you would need to install Knex and also a DataBase driver:

# get knex
$ npm install knex --save

# get bookshelf
$ npm install bookshelf --save

# get one of these DB drivers
$ npm install pg
$ npm install mysql
$ npm install mariasql
$ npm install sqlite3

After installing it (make sure to pass the --save flag so it is added into the package.json file), you can use it in your Node.js application like this:

var knexInstance = require('knex')({
  client: 'mysql', // or what DB you're using
  connection: {
    host     : '127.0.0.1',
    user     : 'scott',
    password : 'tiger', // Scott's cat name
    database : 'db_name',
    charset  : 'utf8'
  }
});
// Initialize Bookshelf by passing the Knex instance
var bookshelf = require('bookshelf')(knexInstance); 

var User = bookshelf.Model.extend({
  tableName: 'users'
});

As you can see, a Bookshelf object is created by passing a Knex instance as a parameter. Then, you can use the Model‘s extend() method to create models in your application, just like the User model for the table users in the example above. Keep in mind that the bookshelf is the only instance of Bookshelf you should use throughout your application. So it’s better to make it accessible everywhere in your application, such as wrapping it in a singleton or put it in a different file and require it when needed.

Bookshelf allows you to make one-to-one, one-to-many, and many-to-many relations. In our case, it would be something like:

var User = bookshelf.Model.extend({
  tableName: 'users',
  posts: function() {
    return this.hasMany(Post);
  }
});

var Post = bookshelf.Model.extend({
  tableName: 'posts',
  user: function() {
    return this.belongsTo(User);
  }
});

In case you want to take a look at it, you can find Bookshelf on GitHub.

Sequelize

Sequelize is another ORM for Node.js and io.js (which are finally merging together). It supports PostgreSQL, MySQL, MariaDB, SQLite and MSSQL and features solid transaction support, relations, read replication, and
more. You can install it by running the following commands:

# Install Sequelize
$ npm install --save sequelize

# Install the DB driver
$ npm install --save pg pg-hstore

# For both mysql and mariadb dialects
$ npm install --save mysql 
$ npm install --save sqlite3

# MSSQL
$ npm install --save tedious

Now you are ready to use it as shown in the example below:

var Sequelize = require('sequelize');
var sequelize = new Sequelize('database', 'username', 'password', {
  host: 'localhost',
  dialect: 'mysql'|'mariadb'|'sqlite'|'postgres'|'mssql', // use one of these

  pool: {
    max: 5,
    min: 0,
    idle: 10000
  },

  // SQLite only
  storage: 'path/to/database.sqlite'
});

// Or you can simply use a connection uri
var sequelize = new Sequelize('postgres://user:pass@example.com:5432/dbname');

Just like with Bookshelf.js, you need only one connection to the database. After that, you can create a model like:

var User = sequelize.define('user', {
  firstName: {
    type: Sequelize.STRING,
    field: 'first_name' // `first_name` column matches User.firstName
  },
  lastName: {
    type: Sequelize.STRING
  }
}, {
  freezeTableName: true // Model tableName (`user`) will be the same as the model name
});

The above Sequelize.STRING matches a VARCHAR in SQL. Other data types are Sequelize.INTEGER for INTEGER, Sequelize.BLOB for BLOB (or bytea in Postgres). You can read the full list here.

Sequelize allows you to write relations between the tables. For example, if you have a model called Project and another one called Developer and want to assign more than one developer to one project, you can do it like this:

Project.hasMany(Developer, {as: 'devs'})

This will make sure to add the necessary fields in each model (project_id to the Developer model in this case). Or if you feel you can’t profit from the Sequelize API, you can run raw SQL queries.

Sequelize can be found on GitHub as well

Lovefiled

Lovefield is not a real ORM. It’s actually a relational database for web apps, built upon IndexedDB, developed by Google and written entirely in JavaScript. It doesn’t support raw SQL queries, but it comes with an API that tries to mimic the SQL syntax.

You can install it using Bower:

$ bower install lovefield --save

or npm:

$ npm install lovefield --save

After adding it in your HTML file, you can start using it as a front-end relational database. Creating databases and tables is simple:

// create the database for a `To Do list`
var todoDB = lf.schema.create('todo_db', 1);

var item = todoDB.createTable('items')
      .addColumn('id', lf.Type.INTEGER)
      .addColumn('task', lf.Type.STRING)
      .addColumn('deadline', lf.Type.DATE_TIME)
      .addColumn('done', lf.Type.BOOLEAN)
      .addPrimaryKey(['id']);

This code snippet shows how to create a database called todo_db and a table called items with the given columns (id as primary key, task, deadline and done). At this point, to get a list of all the unfinished tasks, the code would be:

todoDB.select()
  .from(item)
  .where(item.done.eq(false))
  .exec(); // exec() returns a Promise

The code above is very similar to SQL, where the same query would be:

SELECT * 
    FROM todo_db.items 
    WHERE done = FALSE;

Also you can do ordering, like this:

todoDB.select()
  .from(item)
  .where(item.done.eq(false))
  .orderBy(item.deadline, lf.Order.DESC) // order by deadline
  .exec();

Besides these simple queries, Lovefield is also able to handle more complex queries, such as joins. If I have references in two tables called project and developer (referencing the tables projects and developers respectively) and want to see all the projects of a given developer, I would write:

db.select()
  .from(developer, project)
  .where(lf.op.and(
    developer.projectId.eq(project.id),
    developer.id.eq('12345')
  ))
  .exec();

// these are both equivalent
db.select()
  .from(developer)
  .innerJoin(project, developer.projectId.eq(project.id))
  .where(developer.id.eq('12345'))
  .exec();

So you can see that Lovefield acts as a SQL layer on top of IndexedDB. It also supports ACID transactions (Atomicity, Consistency, Isolation, Durability), limiting and skipping (useful when paginating), parametrized queries, and much more.

Just like the other ORMs, you can download Lovefield from GitHub.

Conclusions

The knowledge of SQL is a skill that every developer should have, but writing SQL queries is boring, especially when there are so many ORMs out there. When they make your job simpler, why not use them in the first place? In this article I’ve covered some of the most important ORMs released so far. Thanks to the examples provided for each of them, you should now be able to make a conscious decision about which of them to use and which fits you needs.

How about you? Which JavaScript ORM do you use? Comment your choice below.

  • Steve Husting

    All right, what’s an ORM?

    • Bouchaala Reda

      ORM – Object Relational Mapper. The name sounds scary, but it really is not once you understand word by word. Mapper, means that it maps from something to the other, in both ways. So, what does it map ? *Object*s, and *Relational* Databases.

      Hence, an ORM is a utility library that helps us, reason about both our code and our database in the well-known object oriented way. What it does is that, it maps between your database, and your objects (or models). You can say, that the major feature ORMs give us, is decoupling. Decoupling our models from our database. Do more research, my explanation is far from what you can find out there! :)

    • Peter Andreas Moelgaard

      Some people… It’s well defined in the intro of the post and easily determined by the references mentioned by OP… Stop trolling when someone makes an effort and shares something with you for free… Go find a fence to stare at instead !

    • Tim Erwin

      what is google?

  • Bouchaala Reda

    Thank you! That was instructive.

  • Thanks for sharing such an useful information Aldo!

  • JB

    Regarding this ORM thing: you should always include definitions for your abbreviations the first time you use it. That way your readers understand what you are talking about.

    • Peter Andreas Moelgaard

      How many definitions of ORM do you operate with in JS (do I have to define that JS means JavaScript too so you won’t be confused) ?

  • jwhitehorn

    “Which JavaScript ORM do you use? Comment your choice below.”

    I use OnionRM, but I might be biased.

  • We used Sequelize at Verizon Cloud and are pretty happy with it.

  • Mikael Lepistö

    Looks like according to documentation Lucid is pretty much lightweight wrapper using knex.js under the hood similar to Bookshelf.

    Is there any extra support for transactions in Lucid or does one has to use knex directly to make it happen?

    Also is there any way to bind adonises validation library to certain model to be able to apply validation every time when model is created from data sent by untrusted party. I couldn’t find these from documentation page…

    • thetutlage

      Disclaimer: I am the author

      Lucid is way more expressive than Bookshelf, it may not matter in early stage, but later clean code makes the difference. Let’s take an example of fetching data for relationships.

      With Bookshelf.

      User.fetch({withRelated:['posts']})

      With Lucid

      yield User.posts().fetch()

      I hope you can see the difference.

      I am more then actively working on Adonis framework and do have in mind to ease the transactions support out of the box.

      As far as model to validation is concerned I believe i am more inclined towards validating requests using service providers. Where you can do something like this inside your controllers

      yield this.validateRequest(User.rules)

      // write your code if all went fine.

      Also, Lucid has support for

      1. Query scopes.

      2. Getters and Setters.

      • Sasha Papchenko

        you can do things like that with Bookshelf.js too.

        User.posts().fetch().then(function(posts){ // do something with posts collection here});

        In such way you can fetch only posts without fetching User. But is you want fetch User with his Posts alltogether, you can use your solution:

        User.fetch({withRelated:[‘posts’]}).then(function(user){\ user with posts eagarly loaded})

      • Sasha Papchenko

        Transactions are supported by Bookshelf too.
        Bookshelf.transaction(function (t){
        //perform some transaction things here.
        User.save(null, {transacting: t}); // this save will be in transaction;
        Post.save(null, {transacting: t}); //this post uses the same transaction, so if we failed to save Post, User changes will be rolledBack.
        });

      • Aaron

        I have used Lucid and Sequelize, the documentation on Lucid although is much less, is actually easier to understand.

        One thing Lucid has done which I have not found out how to in Sequelize (I read that it cant be done yet), is to limit the results from joins.

        Lucid may have used a different way to achieve it under the hood, but it does not really matter for me as long as it gets the job done with as little code as possible.

        Also, my preference is using yield and generators instead of promises

  • Sasha Papchenko

    Bookshelf implements Data Mapper pattern. You can test your models without DB .This is a big advantage over Active Record, whare Data persistance mechanizm is wired to model implementation, like in RoR.

  • Peter Andreas Moelgaard

    Agreed… Abandoned Sequelize many years ago… Surprised to see it on this list !

    • Jax Cavalera

      When I was looking at what to use for working with postgreSQL sequelize was the only thing that came up.. it wasn’t till I tried implementing it and was like HUH? how is this going to work that I stumbled onto pg-promise which is looking… erm promising pardon the pun :)

  • Peter Andreas Moelgaard

    Waterline from SailsJS and Loopback Datasource Juggler from Strongloop

  • Really didn’t know about this. Looks awesome :-)

  • foo bar

    Bookshelf is the best. It’s like Eloquent from Laravel for folks having a PHP background.

    • Jax Cavalera

      I had a guy a week ago that couldn’t find out how to use code surrounding the model. callback. I took a look at the bookshelf documentation to see if it was there but it turns out.. the documentation wasn’t very clear about exactly how to use some things.

      With better, real use-case examples, bookshelf could be a pretty decent option for beginners but until then I think it is best suited to coders with some prior experiences as you say.

      • foo bar

        Seriously ? Maybe for HUGE JS beginners whom didn’t know how to handle async, promise, lodash and managing relationships from an orm and the the underlaying SQL layer. It’s not linked to the library itselft but the dev language skills…
        Intrinsically Bookshelf is pretty neat and easy to use really !

        • Jax Cavalera

          I would say that in the context a beginner.. it’s not huge to consider they won’t have much experience with async, promise, lodash or using an orm to manage the underlying sql layer.. that’s kind of what beginner implies… little or no prior experience in an environment.

          I agree the documentation looks well presented and they explain WHAT each component does, they just don’t show HOW or WHY you would use it to achieve specific outcomes in a way that is easily understood by a beginner who has little or no prior experience working with the sql layer via an ORM.

          This does not mean I think Bookshelf.js is a bad product or even a lower quality one than alternative ORM’s, it is simply my personal experience that I found the documentation hard to apply to real case situations. This isn’t a unique experience for just bookshelf documentation.

          It would seem that a lot of documentation is very clear on WHAT things do and some even show you HOW to use them in examples. Almost none explain WHY you would be using this .. what it’s typical use case is and what can go wrong if you don’t use it.

          For a beginner that last part will save them days of hard learning by trial and error, which I don’t believe is a necessary ingredient in a learning experience if it can be avoided by providing some information about WHY and WHAT can go wrong when using components of a module/library etc.

          The only difference between a beginner and a veteran is that the veteran has learnt from trial and error WHY certain things should or should not be used. If documentation touched on this subject.. those libraries/modules would see faster growth from rapid consumption where the end user can quickly get results since they are informed about more caveats applicable to the components of the library/module they are using/reading up on.

  • Jax Cavalera

    Been working with pg-promise and it beats using ORM’s definitely why declare something twice this has dramatically simplified my experience working between postgresql and node

  • Luis Alberto Romero Calderon

    I use sequelize years ago and still using it, the ORM is very complete, you got everything, well query api, migrations, seeds, everything. I recommend it.

Recommended
Sponsors
Get the latest in JavaScript, once a week, for free.