Fork me on GitHub

bookshelf.js

Build Status Dependency Status devDependency Status

Bookshelf is a JavaScript ORM for Node.js, built on the Knex SQL query builder. Featuring both promise based and traditional callback interfaces, providing transaction support, eager/nested-eager relation loading, polymorphic associations, and support for one-to-one, one-to-many, and many-to-many relations.

It is designed to work well with PostgreSQL, MySQL, and SQLite3.

Website and documentation. The project is hosted on GitHub, and has a comprehensive test suite.

Introduction

Bookshelf aims to provide a simple library for common tasks when querying databases in JavaScript, and forming relations between these objects, taking a lot of ideas from the the Data Mapper Pattern.

With a concise, literate codebase, Bookshelf is simple to read, understand, and extend. It doesn't force you to use any specific validation scheme, provides flexible and efficient relation/nested-relation loading, and first class transaction support.

It's a lean Object Relational Mapper, allowing you to drop down to the raw knex interface whenever you need a custom query that doesn't quite fit with the stock conventions.

Installation

You'll need to install a copy of knex.js, and either mysql, pg, or sqlite3 from npm.

$ npm install knex --save
$ npm install bookshelf --save

# Then add one of the following:
$ npm install pg
$ npm install mysql
$ npm install mariasql
$ npm install sqlite3

The Bookshelf library is initialized by passing an initialized Knex client instance. The knex documentation provides a number of examples for different databases.

var knex = require('knex')({
  client: 'mysql',
  connection: {
    host     : '127.0.0.1',
    user     : 'your_database_user',
    password : 'your_database_password',
    database : 'myapp_test',
    charset  : 'utf8'
  }
});

var bookshelf = require('bookshelf')(knex);

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

This initialization should likely only ever happen once in your application. As it creates a connection pool for the current database, you should use the bookshelf instance returned throughout your library. You'll need to store this instance created by the initialize somewhere in the application so you can reference it. A common pattern to follow is to initialize the client in a module so you can easily reference it later:

// In a file named something like bookshelf.js
var knex = require('knex')(dbConfig);
module.exports = require('bookshelf')(knex);

// elsewhere, to use the bookshelf client:
var bookshelf = require('./bookshelf');

var Post = bookshelf.Model.extend({
  // ...
});

Examples

Here is an example to get you started:

var knex = require('knex')({client: 'mysql', connection: process.env.MYSQL_DATABASE_CONNECTION });
var bookshelf = require('bookshelf')(knex);

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

var Posts = bookshelf.Model.extend({
  tableName: 'messages',
  tags: function() {
    return this.belongsToMany(Tag);
  }
});

var Tag = bookshelf.Model.extend({
  tableName: 'tags'
})

User.where('id', 1).fetch({withRelated: ['posts.tags']}).then(function(user) {
  console.log(user.related('posts').toJSON());
}).catch(function(err) {
  console.error(err);
});

Plugins

  • Registry: Register models in a central location so that you can refer to them using a string in relations instead of having to require it every time. Helps deal with the challenges of circular module dependencies in Node.
  • Virtuals: Define virtual properties on your model to compute new values.
  • Visibility: Specify a whitelist/blacklist of model attributes when serialized toJSON.
  • Pagination: Adds fetchPage methods to use for pagination in place of fetch and fetchAll.

Community plugins

  • bookshelf-cascade-delete - Cascade delete related models on destroy.
  • bookshelf-json-columns - Parse and stringify JSON columns on save and fetch instead of manually define hooks for each model (PostgreSQL and SQLite).
  • bookshelf-mask - Similar to Visibility but supporting multiple scopes, masking models and collections using the json-mask API.
  • bookshelf-schema - A plugin for handling fields, relations, scopes and more.
  • bookshelf-signals - A plugin that translates Bookshelf events to a central hub.
  • bookshelf-paranoia - Protect your database from data loss by soft deleting your rows.
  • bookshelf-uuid - Automatically generates UUIDs for your models.
  • bookshelf-modelbase - An alternative to extend Model, adding timestamps, attribute validation and some native CRUD methods.
  • bookshelf-advanced-serialization - A more powerful visibility plugin, supporting serializing models and collections according to access permissions, application context, and after ensuring relations have been loaded.

Support

Have questions about the library? Come join us in the #bookshelf freenode IRC channel for support on knex.js and bookshelf.js, or post an issue on Stack Overflow or in the GitHub issue tracker.

F.A.Q.

Can I use standard node.js style callbacks?

Yes - you can call .asCallback(function(err, resp) { on any "sync" method and use the standard (err, result) style callback interface if you prefer.

My relations don't seem to be loading, what's up?

Make sure you check that the type is correct for the initial parameters passed to the initial model being fetched. For example new Model({id: '1'}).load([relations...]) will not return the same as Model({id: 1}).load([relations...]) - notice that the id is a string in one case and a number in the other. This can be a common mistake if retrieving the id from a url parameter.

This is only an issue if you're eager loading data with load without first fetching the original model. Model({id: '1'}).fetch({withRelated: [relations...]}) should work just fine.

My process won't exit after my script is finished, why?

The issue here is that Knex, the database abstraction layer used by Bookshelf, uses connection pooling and thus keeps the database connection open. If you want your process to exit after your script has finished, you will have to call .destroy(cb) on the knex property of your Bookshelf instance or on the Knex instance passed during initialization. More information about connection pooling can be found over at the Knex docs.

How do I debug?

If you pass {debug: true} as one of the options in your initialize settings, you can see all of the query calls being made. Sometimes you need to dive a bit further into the various calls and see what all is going on behind the scenes. I'd recommend node-inspector, which allows you to debug code with debugger statements like you would in the browser.

Bookshelf uses its own copy of the "bluebird" promise library, you can read up here for more on debugging these promises... but in short, adding:

process.stderr.on('data', function(data) {
  console.log(data);
});

At the start of your application code will catch any errors not otherwise caught in the normal promise chain handlers, which is very helpful in debugging.

How do I run the test suite?

The test suite looks for an environment variable called BOOKSHELF_TEST for the path to the database configuration. If you run the following command: $ export BOOKSHELF_TEST='/path/to/your/bookshelf_config.js', replacing with the path to your config file, and the config file is valid, the test suite should run with npm test.

Also note that you will have to create the appropriate database(s) for the test suite to run. For example, with MySQL, you'll need to run the command create database bookshelf_test; in addition to exporting the correct test settings prior to running the test suite.

Can I use Bookshelf outside of Node.js?

While it primarily targets Node.js, all dependencies are browser compatible, and it could be adapted to work with other javascript environments supporting a sqlite3 database, by providing a custom Knex adapter.

Which open-source projects are using Bookshelf?

We found the following projects using Bookshelf, but there can be more:

  • Ghost (A blogging platform) uses bookshelf. [Link]
  • Soapee (Soap Making Community and Resources) uses bookshelf. [Link]
  • NodeZA (Node.js social platform for developers in South Africa) uses bookshelf. [Link]
  • Sunday Cook (A social cooking event platform) uses bookshelf. [Link]
  • FlyptoX (Open-source Node.js cryptocurrency exchange) uses bookshelf. [Link]
  • And of course, everything on here use bookshelf too.

Associations

Bookshelf handles one-to-one, one-to-many, and many-to-many associations by defining relationships on models.

One-to-one

One-to-one associations can be created with belongsTo, hasOne, and morphOne relation types.

var Book = bookshelf.Model.extend({
  tableName: 'books',
  summary: function() {
    return this.hasOne(Summary);
  }
});

var Summary = bookshelf.Model.extend({
  tableName: 'summaries',
  book: function() {
    return this.belongsTo(Book);
  }
});

A Knex migration for the above relationship could be created with:

exports.up = function(knex, Promise) {
  return knex.schema.createTable('books', function(table) {
    table.increments('id').primary();
    table.string('name');
  }).createTable('summaries', function(table) {
    table.increments('id').primary();
    table.string('details');
    table.integer('book_id').unique().references('books.id');
  });
};

exports.down = function(knex, Promise) {
  return knex.schema.dropTable('books')
    .dropTable('summaries');
};

One-to-many

One-to-many associations can be created with belongsTo, hasMany, morphMany / morphTo, and some of the through relation types.

var Book = bookshelf.Model.extend({
  tableName: 'books',
  pages: function() {
    return this.hasMany(Page);
  }
});

var Page = bookshelf.Model.extend({
  tableName: 'pages',
  book: function() {
    return this.belongsTo(Book);
  }
});

A Knex migration for the above relationship could be created with:

exports.up = function(knex, Promise) {
  return knex.schema.createTable('books', function(table) {
    table.increments('id').primary();
    table.string('name');
  }).createTable('pages', function(table) {
    table.increments('id').primary();
    table.string('content');
    table.integer('book_id').references('books.id')
  });
};

exports.down = function(knex, Promise) {
  return knex.schema.dropTable('books')
    .dropTable('pages');
};

Many-to-many

Many-to-many associations can be created with belongsToMany, and through relation types.

var Book = bookshelf.Model.extend({
  tableName: 'books',
  authors: function() {
    return this.belongsToMany(Author);
  }
});

var Author = bookshelf.Model.extend({
  tableName: 'authors',
  books: function() {
    return this.belongsToMany(Book);
  }
});

A Knex migration for the above relationship could be created with:

exports.up = function(knex, Promise) {
  return knex.schema.createTable('books', function(table) {
    table.increments('id').primary();
    table.string('name');
  }).createTable('authors', function(table) {
    table.increments('id').primary();
    table.string('name');
  }).createTable('authors_books', function(table) {
    table.integer('author_id').references('authors.id');
    table.integer('book_id').references('books.id');
  });
};

exports.down = function(knex, Promise) {
  return knex.schema.dropTable('books')
    .dropTable('authors')
    .dropTable('authors_books');
};

Polymorphic

With polymorphic associations, a model can belong to more than one other model, on a single association. For example, you might have a photo model that belongs to either a Site model or a Post model. Here’s how this could be declared:

var Site = bookshelf.Model.extend({
  tableName: 'sites',
  photo: function() {
    return this.morphOne(Photo, 'imageable');
  }
});

var Post = bookshelf.Model.extend({
  tableName: 'posts',
  photos: function() {
    return this.morphMany(Photo, 'imageable');
  }
});

var Photo = bookshelf.Model.extend({
  tableName: 'photos',
  imageable: function() {
    return this.morphTo('imageable', Site, Post);
  }
});

Optionally, if you wish to use column names other than the name suffixed with _type and _id (for example, if you use a different naming convention in your database), you may specify custom columnNames. This argument, when specified, expects an array containing the substitute _type and _id columns, respectively.

Note that any custom columnNames must be specified on both ends of the relationship! Examples are provided for each of the polymorphic relationship types individually.

Bookshelf

The Bookshelf library is initialized by passing an initialized Knex client instance. The knex documentation provides a number of examples for different databases.

Construction

new Bookshelf(knex) source

Parameters
  • knex Knex

    Knex instance.

Members

bookshelf.knex :Knex source

A reference to the Knex.js instance being used by Bookshelf.

Methods

bookshelf.transaction(transactionCallback) → Promise source

Parameters
Returns
Promise

A promise resolving to the value returned from transactionCallback.

An alias to Knex#transaction, the transaction object must be passed along in the options of any relevant Bookshelf calls, to ensure all queries are on the same connection. The entire transaction block is a promise that will resolve when the transaction is committed, or fail if the transaction is rolled back.

var Promise = require('bluebird');

Bookshelf.transaction(function(t) {
  return new Library({name: 'Old Books'})
    .save(null, {transacting: t})
    .tap(function(model) {
      return Promise.map([
        {title: 'Canterbury Tales'},
        {title: 'Moby Dick'},
        {title: 'Hamlet'}
      ], function(info) {
        // Some validation could take place here.
        return new Book(info).save({'shelf_id': model.id}, {transacting: t});
      });
    });
}).then(function(library) {
  console.log(library.related('books').pluck('title'));
}).catch(function(err) {
  console.error(err);
});

Type Definitions

transactionCallback(transaction) → Promise source

Parameters
  • transaction Transaction
See
Returns
Promise

A transaction block to be provided to Bookshelf#transaction.

Model

Models are simple objects representing individual database rows, specifying the tableName and any relations to other models. They can be extended with any domain-specific methods, which can handle components such as validations, computed properties, and access control.

Construction

new Model(attributes, [options]) source

Parameters
  • attributes Object

    Initial values for this model's attributes.

  • [options] Object

    Hash of options.

    • [tableName] string

      Initial value for tableName.

    • [hasTimestamps=false] boolean

      Initial value for hasTimestamps.

    • [parse=false] boolean

      Convert attributes by parse before being set on the model.

When creating an instance of a model, you can pass in the initial values of the attributes, which will be set on the model. If you define an initialize function, it will be invoked when the model is created.

new Book({
  title: "One Thousand and One Nights",
  author: "Scheherazade"
});

In rare cases, if you're looking to get fancy, you may want to override constructor, which allows you to replace the actual constructor function for your model.

let Book = bookshelf.Model.extend({
  tableName: 'documents',
  constructor: function() {
    bookshelf.Model.apply(this, arguments);
    this.on('saving', function(model, attrs, options) {
      options.query.where('type', '=', 'book');
    });
  }
});

model.initialize(attributes, [options]) source

Parameters
  • attributes Object

    Initial values for this model's attributes.

  • [options] Object

    The hash of options passed to constructor.

See

Called by the Model constructor when creating a new instance. Override this function to add custom initialization, such as event listeners.

Static

Model.collection([models], [options])Collection source

Example
Customer.collection().fetch().then(function(collection) {
  // ...
});
Parameters
  • [models] Model[]
  • [options] Object
Returns
Collection

A simple static helper to instantiate a new Collection, setting the current model as the collection's target.

Model.count([column], [options]) → Promise source

Parameters
  • [column='*'] string

    Specify a column to count - rows with null values in this column will be excluded.

  • [options] Object

    Hash of options.

Since
  • 0.8.2
Returns
Promise

A promise resolving to the number of matching rows.

Gets the number of matching records in the database, respecting any previous calls to query. If a column is provided, records with a null value in that column will be excluded from the count.

Model.extend([prototypeProperties], [classProperties]) → function source

Parameters
  • [prototypeProperties] Object

    Instance methods and properties to be attached to instances of the new class.

  • [classProperties] Object

    Class (ie. static) functions and properties to be attached to the constructor of the new class.

Returns
function

Constructor for new Model subclass.

To create a Model class of your own, you extend bookshelf.Model.

extend correctly sets up the prototype chain, so subclasses created with extend can be further extended and subclassed as far as you like.

var checkit  = require('checkit');
var Promise  = require('bluebird');
var bcrypt   = Promise.promisifyAll(require('bcrypt'));

var Customer = bookshelf.Model.extend({
  initialize: function() {
    this.on('saving', this.validateSave);
  },

  validateSave: function() {
    return checkit(rules).run(this.attributes);
  },

  account: function() {
    return this.belongsTo(Account);
  },
}, {
  login: Promise.method(function(email, password) {
    if (!email || !password) throw new Error('Email and password are both required');
    return new this({email: email.toLowerCase().trim()}).fetch({require: true}).tap(function(customer) {
      return bcrypt.compareAsync(password, customer.get('password'))
        .then(function(res) {
          if (!res) throw new Error('Invalid password');
        });
    });
  })
});

Customer.login(email, password)
  .then(function(customer) {
    res.json(customer.omit('password'));
  }).catch(Customer.NotFoundError, function() {
    res.json(400, {error: email + ' not found'});
  }).catch(function(err) {
    console.error(err);
  });

Brief aside on super: JavaScript does not provide a simple way to call super — the function of the same name defined higher on the prototype chain. If you override a core function like set, or save, and you want to invoke the parent object's implementation, you'll have to explicitly call it, along these lines:

var Customer = bookshelf.Model.extend({
  set: function() {
    // ...
    bookshelf.Model.prototype.set.apply(this, arguments);
    // ...
  }
});

Model.fetchAll() → Promise<Collection> source

See
Returns
Promise<Collection>

Simple helper function for retrieving all instances of the given model.

Model.forge([attributes], [options]) source

Parameters
  • [attributes] Object

    Initial values for this model's attributes.

  • [options] Object

    Hash of options.

    • [tableName] string

      Initial value for tableName.

    • [hasTimestamps=false] boolean

      Initial value for hasTimestamps.

    • [parse=false] boolean

      Convert attributes by parse before being set on the model.

A simple helper function to instantiate a new Model without needing new.

Members

model.hasTimestamps :boolean|Array source

Sets the current date/time on the timestamps columns created_at and updated_at for a given method. The 'update' method will only update updated_at. To override the default column names, assign an array to hasTimestamps. The first element will be the created column name and the second will be the updated column name.

model.idAttribute :string source

This tells the model which attribute to expect as the unique identifier for each database row (typically an auto-incrementing primary key named "id"). Note that if you are using parse and format (to have your model's attributes in camelCase, but your database's columns in snake_case, for example) this refers to the name returned by parse (myId), not the database column (my_id).

model.tableName :string source

Example
var Television = bookshelf.Model.extend({
  tableName: 'televisions'
});

A required property for any database usage, The tableName property refers to the database table name the model will query against.

Methods

model.belongsTo(Target, [foreignKey])Model source

Parameters
  • Target Model

    Constructor of Model targeted by join.

  • [foreignKey] string

    ForeignKey in this model. By default, the foreignKey is assumed to be the singular form of the Target model's tableName, followed by _id / _{{idAttribute}}.

Returns
Model

The belongsTo relationship is used when a model is a member of another Target model.

It can be used in a one-to-one associations as the inverse of a hasOne. It can also used in one-to-many associations as the inverse of a hasMany (and is the one side of that association). In both cases, the belongsTo relationship is used for a model that is a member of another Target model, referenced by the foreignKey in the current model.

let Book = bookshelf.Model.extend({
  tableName: 'books',
  author: function() {
    return this.belongsTo(Author);
  }
});

// select * from `books` where id = 1
// select * from `authors` where id = book.author_id
Book.where({id: 1}).fetch({withRelated: ['author']}).then(function(book) {
  console.log(JSON.stringify(book.related('author')));
});

model.belongsToMany(Target, [table], [foreignKey], [otherKey])Collection source

Parameters
  • Target Model

    Constructor of Model targeted by join.

  • [table] string

    Name of the joining table. Defaults to the two table names, joined by an underscore, ordered alphabetically.

  • [foreignKey] string

    Foreign key in this model. By default, the foreignKey is assumed to be the singular form of this model's tableName, followed by _id / _{{idAttribute}}.

  • [otherKey] string

    Foreign key in the Target model. By default, the otherKey is assumed to be the singular form of the Target model's tableName, followed by _id / _{{idAttribute}}.

Returns
Collection

Defines a many-to-many relation, where the current model is joined to one or more of a Target model through another table. The default name for the joining table is the two table names, joined by an underscore, ordered alphabetically. For example, a users table and an accounts table would have a joining table of accounts_users.

let Account = bookshelf.Model.extend({
  tableName: 'accounts'
});

let User = bookshelf.Model.extend({
  tableName: 'users',
  allAccounts: function () {
    return this.belongsToMany(Account);
  },
  adminAccounts: function() {
    return this.belongsToMany(Account).query({where: {access: 'admin'}});
  },
  viewAccounts: function() {
    return this.belongsToMany(Account).query({where: {access: 'readonly'}});
  }
});

The default key names in the joining table are the singular versions of the model table names, followed by _id / _{{idAttribute}}. So in the above case, the columns in the joining table would be user_id, account_id, and access, which is used as an example of how dynamic relations can be formed using different contexts. To customize the keys used in, or the tableName used for the join table, you may specify them like so:

 this.belongsToMany(Account, 'users_accounts', 'userid', 'accountid');

If you wish to create a belongsToMany association where the joining table has a primary key, and more information about the model, you may create a belongsToMany through relation:

let Doctor = bookshelf.Model.extend({
  patients: function() {
    return this.belongsToMany(Patient).through(Appointment);
  }
});

let Appointment = bookshelf.Model.extend({
  patient: function() {
    return this.belongsTo(Patient);
  },
  doctor: function() {
    return this.belongsTo(Doctor);
  }
});

let Patient = bookshelf.Model.extend({
  doctors: function() {
    return this.belongsToMany(Doctor).through(Appointment);
  }
});

Collections returned by a belongsToMany relation are decorated with several pivot helper methods. See attach, detach, updatePivot and withPivot for more information.

model.clear()Model source

Returns
Model

This model.

Clear all attributes on the model.

model.clone()Model source

Returns
Model

Cloned instance of this model.

Returns a new instance of the model with identical attributes, including any relations from the cloned model.

model.count([column], [options]) → Promise source

Example
Duck.where('color', 'blue').count('name')
  .then(function(count) { //...
Parameters
  • [column='*'] string

    Specify a column to count - rows with null values in this column will be excluded.

  • [options] Object

    Hash of options.

Since
  • 0.8.2
Returns
Promise

A promise resolving to the number of matching rows.

Gets the number of matching records in the database, respecting any previous calls to Model#query.

model.destroy([options]) → Promise<Model> source

Example
new User({id: 1})
  .destroy()
  .then(function(model) {
    // ...
  });
Parameters
  • [options] Object

    Hash of options.

    • [transacting] Transaction

      Optionally run the query in a transaction.

    • [require=true] bool

      Throw a Model.NoRowsDeletedError if no records are affected by destroy.

Fires
Throws
Model.NoRowsDeletedError
Returns
Promise<Model>

A promise resolving to the destroyed and thus "empty" model.

destroy performs a delete on the model, using the model's idAttribute to constrain the query.

A "destroying" event is triggered on the model before being destroyed. To prevent destroying the model (with validation, etc.), throwing an error inside one of these event listeners will stop destroying the model and reject the promise.

A "destroyed" event is fired after the model's removal is completed.

model.escape(attribute) → string source

Parameters
  • attribute string

    The attribute to escape.

Returns
string

HTML-escaped value of an attribute.

Get the HTML-escaped value of an attribute.

model.fetch([options]) → Promise<Model|null> source

Parameters
  • [options] Object

    Hash of options.

    • [require=false] boolean

      Reject the returned response with a NotFoundError if results are empty.

    • [columns='*'] string|string[]

      Specify columns to be retrieved.

    • [transacting] Transaction

      Optionally run the query in a transaction.

    • [withRelated] string|Object|mixed[]

      Relations to be retrieved with Model instance. Either one or more relation names or objects mapping relation names to query callbacks.

Fires
Throws
Model.NotFoundError
Returns
Promise<Model|null>

A promise resolving to the fetched model or null if none exists.

Fetches a model from the database, using any attributes currently set on the model to form a select query.

A "fetching" event will be fired just before the record is fetched; a good place to hook into for validation. "fetched" event will be fired when a record is successfully retrieved.

If you need to constrain the query performed by fetch, you can call query before calling fetch.

// select * from `books` where `ISBN-13` = '9780440180296'
new Book({'ISBN-13': '9780440180296'})
  .fetch()
  .then(function(model) {
    // outputs 'Slaughterhouse Five'
    console.log(model.get('title'));
  });

If you'd like to only fetch specific columns, you may specify a columns property in the options for the fetch call, or use query, tapping into the Knex column method to specify which columns will be fetched.

single property, or an array of properties can be specified as a value for the withRelated property. You can also execute callbacks on relations queries (eg. for sorting a relation). The results of these relation queries will be loaded into a relations property on the model, may be retrieved with the related method, and will be serialized as properties on a toJSON call unless {shallow: true} is passed.

let Book = bookshelf.Model.extend({
  tableName: 'books',
  editions: function() {
    return this.hasMany(Edition);
  },
  chapters: function() {
    return this.hasMany(Chapter);
  },
  genre: function() {
    return this.belongsTo(Genre);
  }
})

new Book({'ISBN-13': '9780440180296'}).fetch({
  withRelated: [
    'genre', 'editions',
    { chapters: function(query) { query.orderBy('chapter_number'); }}
  ]
}).then(function(book) {
  console.log(book.related('genre').toJSON());
  console.log(book.related('editions').toJSON());
  console.log(book.toJSON());
});

model.fetchAll([options]) → Promise<Collection> source

Parameters
  • [options] Object

    Hash of options.

    • [require=false] boolean

      Rejects the returned promise with an Collection.EmptyError if no records are returned.

    • [transacting] Transaction

      Optionally run the query in a transaction.

Fires
Throws
Collection.EmptyError

Rejects the promise in the event of an empty response if the require: true option.

Returns
Promise<Collection>

A promise resolving to the fetched collection.

Fetches a collection of models from the database, using any query parameters currently set on the model to form a select query. Returns a promise, which will resolve with the fetched collection. If you wish to trigger an error if no models are found, pass {require: true} as one of the options to the fetchAll call.

If you need to constrain the query performed by fetch, you can call the query method before calling fetch.

model.fetchPage(options) → Promise<Model|null> source

Example
Car
.query(function (qb) {
   qb.innerJoin('manufacturers', 'cars.manufacturer_id', 'manufacturers.id');
   qb.groupBy('cars.id');
   qb.where('manufacturers.country', '=', 'Sweden');
})
.orderBy('-productionYear') // Same as .orderBy('cars.productionYear', 'DESC')
.fetchPage({
   pageSize: 15, // Defaults to 10 if not specified
   page: 3, // Defaults to 1 if not specified

   // OR
   // limit: 15,
   // offset: 30,

   withRelated: ['engine'] // Passed to Model#fetchAll
})
.then(function (results) {
   console.log(results); // Paginated results object with metadata example below
})

// Pagination results:

{
   models: [<Car>], // Regular bookshelf Collection
   // other standard Collection attributes
   ...
   pagination: {
       rowCount: 53, // Total number of rows found for the query before pagination
       pageCount: 4, // Total number of pages of results
       page: 3, // The requested page number
       pageSze: 15, // The requested number of rows per page

 // OR, if limit/offset pagination is used instead of page/pageSize:
       // offset: 30, // The requested offset
       // limit: 15 // The requested limit
   }
}
Parameters
  • options object

    The pagination options, plus any additional options that will be passed to Model#fetchAll

Returns
Promise<Model|null>

model.format(attributes) → Object source

Parameters
  • attributes Object

    The attributes to be converted.

Returns
Object

Formatted attributes.

The format method is used to modify the current state of the model before it is persisted to the database. The attributes passed are a shallow clone of the model, and are only used for inserting/updating - the current values of the model are left intact.

model.get(attribute) → mixed source

Example
note.get("title");
Parameters
  • attribute string

    The name of the attribute to retrieve.

Returns
mixed

Attribute value.

Get the current value of an attribute from the model.

model.has(attribute) → bool source

Parameters
  • attribute string

    The attribute to check.

Returns
bool

True if attribute is set, otherwise null.

Returns true if the attribute contains a value that is not null or undefined.

model.hasChanged([attribute]) → bool source

Parameters
  • [attribute] string
Returns
bool

true if any attribute has changed. Or, if attribute was specified, true if it has changed.

Returns true if any attribute attribute has changed since the last fetch, save, or destroy. If an attribute is passed, returns true only if that specific attribute has changed.

model.hasMany(Target, [foreignKey])Collection source

Parameters
  • Target Model

    Constructor of Model targeted by join.

  • [foreignKey] string

    ForeignKey in the Target model. By default, the foreignKey is assumed to be the singular form of this model's tableName, followed by _id / _{{idAttribute}}.

Returns
Collection

The hasMany relation specifies that this model has one or more rows in another table which match on this model's primary key.

let Author = bookshelf.Model.extend({
  tableName: 'authors',
  books: function() {
    return this.hasMany(Book);
  }
});

// select * from `authors` where id = 1
// select * from `books` where author_id = 1
Author.where({id: 1}).fetch({withRelated: ['books']}).then(function(author) {
  console.log(JSON.stringify(author.related('books')));
});

model.hasOne(Target, [foreignKey])Model source

Parameters
  • Target Model

    Constructor of Model targeted by join.

  • [foreignKey] string

    ForeignKey in the Target model. By default, the foreignKey is assumed to be the singular form of this model's tableName, followed by _id / _{{idAttribute}}.

Returns
Model

The hasOne relation specifies that this table has exactly one of another type of object, specified by a foreign key in the other table.

let Record = bookshelf.Model.extend({
  tableName: 'health_records'
});

let Patient = bookshelf.Model.extend({
  tableName: 'patients',
  record: function() {
    return this.hasOne(Record);
  }
});

// select * from `health_records` where `patient_id` = 1;
new Patient({id: 1}).related('record').fetch().then(function(model) {
  // ...
});

// alternatively, if you don't need the relation loaded on the patient's relations hash:
new Patient({id: 1}).record().fetch().then(function(model) {
  // ...
});

model.isNew() source

Example
var modelA = new bookshelf.Model();
modelA.isNew(); // true

var modelB = new bookshelf.Model({id: 1});
modelB.isNew(); // false

Checks for the existence of an id to determine whether the model is considered "new".

model.load(relations, [options]) → Promise<Model> source

Example
new Posts().fetch().then(function(collection) {
  collection.at(0)
  .load(['author', 'content', 'comments.tags'])
  .then(function(model) {
    JSON.stringify(model);
  });
});

{
  title: 'post title',
  author: {...},
  content: {...},
  comments: [
    {tags: [...]}, {tags: [...]}
  ]
}
Parameters
  • relations string|string[]

    The relation, or relations, to be loaded.

  • [options] Object

    Hash of options.

    • [transacting] Transaction

      Optionally run the query in a transaction.

Returns
Promise<Model>

A promise resolving to this model

The load method takes an array of relations to eager load attributes onto a Model, in a similar way that the withRelated property works on fetch. Dot separated attributes may be used to specify deep eager loading.

model.morphMany(Target, [name], [columnNames], [morphValue])Collection source

Parameters
  • Target Model

    Constructor of Model targeted by join.

  • [name] string

    Prefix for _id and _type columns.

  • [columnNames] string[]

    Array containing two column names, the first is the _type, the second is the _id.

  • [morphValue=Target#tablename] string

    The string value associated with this relationship. Stored in the _type column of the polymorphic table. Defaults to Target# tablename.

Returns
Collection

A collection of related models.

morphMany is essentially the same as a morphOne, but creating a collection rather than a model (similar to a hasOne vs. hasMany relation).

morphMany is used to signify a one-to-many or many-to-many polymorphic relation with another Target model, where the name of the model is used to determine which database table keys are used. The naming convention requires the name prefix an _id and _type field in the database. So for the case below the table names would be imageable_type and imageable_id. The morphValue may be optionally set to store/retrieve a different value in the _type column than the Target's tableName.

let Post = bookshelf.Model.extend({
  tableName: 'posts',
  photos: function() {
    return this.morphMany(Photo, 'imageable');
  }
});

And with custom columnNames:

let Post = bookshelf.Model.extend({
  tableName: 'posts',
  photos: function() {
    return this.morphMany(Photo, 'imageable', ["ImageableType", "ImageableId"]);
  }
});

model.morphOne(Target, [name], [columnNames], [morphValue])Model source

Parameters
  • Target Model

    Constructor of Model targeted by join.

  • [name] string

    Prefix for _id and _type columns.

  • [columnNames] string[]

    Array containing two column names, the first is the _type, the second is the _id.

  • [morphValue=Target#tableName] string

    The string value associated with this relationship. Stored in the _type column of the polymorphic table. Defaults to Target#tableName.

Returns
Model

The related model.

The morphOne is used to signify a one-to-one polymorphic relation with another Target model, where the name of the model is used to determine which database table keys are used. The naming convention requires the name prefix an _id and _type field in the database. So for the case below the table names would be imageable_type and imageable_id. The morphValue may be optionally set to store/retrieve a different value in the _type column than the Model#tableName.

let Site = bookshelf.Model.extend({
  tableName: 'sites',
  photo: function() {
    return this.morphOne(Photo, 'imageable');
  }
});

And with custom columnNames:

let Site = bookshelf.Model.extend({
  tableName: 'sites',
  photo: function() {
    return this.morphOne(Photo, 'imageable', ["ImageableType", "ImageableId"]);
  }
});

Note that both columnNames and morphValue are optional arguments. How your argument is treated when only one is specified, depends on the type. If your argument is an array, it will be assumed to contain custom columnNames. If it's not, it will be assumed to indicate a morphValue.

model.morphTo(name, [columnNames], Target)Model source

Parameters
  • name string

    Prefix for _id and _type columns.

  • [columnNames] string[]

    Array containing two column names, the first is the _type, the second is the _id.

  • Target Model

    Constructor of Model targeted by join.

Returns
Model

The morphTo relation is used to specify the inverse of the morphOne or morphMany relations, where the targets must be passed to signify which models are the potential opposite end of the polymorphic relation.

let Photo = bookshelf.Model.extend({
  tableName: 'photos',
  imageable: function() {
    return this.morphTo('imageable', Site, Post);
  }
});

And with custom columnNames:

let Photo = bookshelf.Model.extend({
  tableName: 'photos',
  imageable: function() {
    return this.morphTo('imageable', ["ImageableType", "ImageableId"], Site, Post);
  }
});

model.off() source

Example
customer.off('fetched fetching');
ship.off(); // This will remove all event listeners
See

model.on() source

Example
customer.on('fetching', function(model, columns) {
  // Do something before the data is fetched from the database
});
See

model.once(nameOrNames, callback) source

Parameters
  • nameOrNames string

    The name of the event or space separated list of events to register a callback for.

  • callback function

    That callback to invoke only once when the event is fired.

Just like Events#on, but causes the bound callback to fire only once before being removed. Handy for saying "the next time that X happens, do this". When multiple events are passed in using the space separated syntax, the event will fire once for every event you passed in, not once for a combination of all events.

model.orderBy(sort, order) source

Example
Car.forge().orderBy('color', 'ASC').fetchAll()
   .then(function (rows) { // ...
Parameters
  • sort string

    Column to sort on

  • order string

    Ascending ('ASC') or descending ('DESC') order

Since
  • 0.9.3

Specifies the column to sort on and sort order.

The order parameter is optional, and defaults to 'ASC'. You may also specify 'DESC' order by prepending a hyphen to the sort column name. orderBy("date", 'DESC') is the same as orderBy("-date").

Unless specified using dot notation (i.e., "table.column"), the default table will be the table name of the model orderBy was called on.

model.parse(response) → Object source

Example
// Example of a "parse" to convert snake_case to camelCase, using `underscore.string`
model.parse = function(attrs) {
  return _.reduce(attrs, function(memo, val, key) {
    memo[_.camelCase(key)] = val;
    return memo;
  }, {});
};
Parameters
  • response Object

    Hash of attributes to parse.

Returns
Object

Parsed attributes.

The parse method is called whenever a model's data is returned in a fetch call. The function is passed the raw database response object, and should return the attributes hash to be set on the model. The default implementation is a no-op, simply passing through the JSON response. Override this if you need to format the database responses - for example calling JSON.parse on a text field containing JSON, or explicitly typecasting a boolean in a sqlite3 database response.

model.previous(attribute) → mixed source

Parameters
  • attribute string

    The attribute to check

Returns
mixed

The previous value

Returns the this previous value of a changed attribute, or undefined if one had not been specified previously.

model.previousAttributes() → Object source

Returns
Object

The attributes as they were before the last change.

Return a copy of the model's previous attributes from the model's last fetch, save, or destroy. Useful for getting a diff between versions of a model, or getting back to a valid state after an error occurs.

model.query(arguments)Model|QueryBuilder source

Example
model
  .query('where', 'other_id', '=', '5')
  .fetch()
  .then(function(model) {
    // ...
  });

model
  .query({where: {other_id: '5'}, orWhere: {key: 'value'}})
  .fetch()
  .then(function(model) {
    // ...
  });

model.query(function(qb) {
  qb.where('other_person', 'LIKE', '%Demo').orWhere('other_id', '>', 10);
}).fetch()
  .then(function(model) {
    // ...
  });

let qb = model.query();
qb.where({id: 1}).select().then(function(resp) {
  // ...
});
Parameters
  • arguments function|Object|string

    The query method.

See
Returns
Model|QueryBuilder

Will return this model or, if called with no arguments, the underlying query builder.

The query method is used to tap into the underlying Knex query builder instance for the current model. If called with no arguments, it will return the query builder directly. Otherwise, it will call the specified method on the query builder, applying any additional arguments from the model.query call. If the method argument is a function, it will be called with the Knex query builder as the context and the first argument, returning the current model.

model.refresh(options) → Promise<Model> source

Parameters
  • options Object

    A hash of options. See Model#fetch for details.

Since
  • 0.8.2
Returns
Promise<Model>

A promise resolving to this model.

Update the attributes of a model, fetching it by its primary key. If no attribute matches its idAttribute, then fetch by all available fields.

Example
new Photo({id: 1}).fetch({
  withRelated: ['account']
}).then(function(photo) {
  if (photo) {
    var account = photo.related('account');
    if (account.id) {
       return account.related('trips').fetch();
    }
  }
});
Parameters
  • name string

    The name of the relation to retrieve.

Returns
Model|Collection|undefined

The specified relation as defined by a method on the model, or undefined if it does not exist.

The related method returns a specified relation loaded on the relations hash on the model, or calls the associated relation method and adds it to the relations hash if one exists and has not yet been loaded.

model.resetQuery()Model source

Returns
Model

Self, this method is chainable.

Used to reset the internal state of the current query builder instance. This method is called internally each time a database action is completed by Sync

model.save([key], [val], [attrs], [options]) → Promise<Model> source

Parameters
  • [key] string

    Attribute name.

  • [val] string

    Attribute value.

  • [attrs] Object

    A hash of attributes.

  • [options] Object
    • [transacting] Transaction

      Optionally run the query in a transaction.

    • [method] string

      Explicitly select a save method, either "update" or "insert".

    • [defaults=false] string

      Assign defaults in an update operation.

    • [patch=false] bool

      Only save attributes supplied in arguments to save.

    • [require=true] bool

      Throw a Model.NoRowsUpdatedError if no records are affected by save.

Fires
Throws
Model.NoRowsUpdatedError
Returns
Promise<Model>

A promise resolving to the saved and updated model.

save is used to perform either an insert or update query using the model's set attributes.

If the model isNew, any defaults will be set and an insert query will be performed. Otherwise it will update the record with a corresponding ID. This behaviour can be overriden with the method option.

new Post({name: 'New Article'}).save().then(function(model) {
  // ...
});

If you only wish to update with the params passed to the save, you may pass a {patch: true} flag to the database:

// update authors set "bio" = 'Short user bio' where "id" = 1
new Author({id: 1, first_name: 'User'})
  .save({bio: 'Short user bio'}, {patch: true})
  .then(function(model) {
    // ...
  });

Several events fired on the model when saving: a "creating", or "updating" event if the model is being inserted or updated, and a "saving" event in either case. To prevent saving the model (with validation, etc.), throwing an error inside one of these event listeners will stop saving the model and reject the promise. A "created", or Model#"updated" event is fired after the model is saved, as well as a "saved" event either way. If you wish to modify the query when the "saving" event is fired, the knex query object should is available in options.query.

// Save with no arguments
Model.forge({id: 5, firstName: "John", lastName: "Smith"}).save().then(function() { //...

// Or add attributes during save
Model.forge({id: 5}).save({firstName: "John", lastName: "Smith"}).then(function() { //...

// Or, if you prefer, for a single attribute
Model.forge({id: 5}).save('name', 'John Smith').then(function() { //...

model.serialize([options]) → Object source

Example
var artist = new bookshelf.Model({
  firstName: "Wassily",
  lastName: "Kandinsky"
});

artist.set({birthday: "December 16, 1866"});

console.log(JSON.stringify(artist));
// {firstName: "Wassily", lastName: "Kandinsky", birthday: "December 16, 1866"}
Parameters
  • [options] Object
    • [shallow=false] bool

      Exclude relations.

    • [omitPivot=false] bool

      Exclude pivot values.

Returns
Object

Serialized model as a plain object.

Return a copy of the model's attributes for JSON stringification. If the model has any relations defined, this will also call toJSON on each of the related objects, and include them on the object unless {shallow: true} is passed as an option.

serialize is called internally by toJSON. Override this function if you want to customize its output.

model.set(attribute, [value], [options])Model source

Example
customer.set({first_name: "Joe", last_name: "Customer"});
customer.set("telephone", "555-555-1212");
Parameters
  • attribute string|Object

    Attribute name, or hash of attribute names and values.

  • [value] mixed

    If a string was provided for attribute, the value to be set.

  • [options] Object
    • [unset=false] Object

      Remove attributes instead of setting them.

Returns
Model

This model.

Set a hash of attributes (one or many) on the model.

model.through(Interim, [throughForeignKey], [otherKey])Collection source

Parameters
  • Interim Model

    Pivot model.

  • [throughForeignKey] string

    Foreign key in this model. By default, the foreignKey is assumed to be the singular form of the Target model's tableName, followed by _id / _{{idAttribute}}.

  • [otherKey] string

    Foreign key in the Interim model. By default, the otherKey is assumed to be the singular form of this model's tableName, followed by _id / _{{idAttribute}}.

Returns
Collection

Helps to create dynamic relations between models and collections, where a hasOne, hasMany, belongsTo, or belongsToMany relation may run through a JoinModel.

A good example of where this would be useful is if a book hasMany paragraphs through chapters. Consider the following examples:

let Book = bookshelf.Model.extend({
  tableName: 'books',

  // Find all paragraphs associated with this book, by
  // passing through the "Chapter" model.
  paragraphs: function() {
    return this.hasMany(Paragraph).through(Chapter);
  },

  chapters: function() {
    return this.hasMany(Chapter);
  }
});

let Chapter = bookshelf.Model.extend({
  tableName: 'chapters',

  paragraphs: function() {
    return this.hasMany(Paragraph);
  }
});

let Paragraph = bookshelf.Model.extend({
  tableName: 'paragraphs',

  chapter: function() {
    return this.belongsTo(Chapter);
  },

  // A reverse relation, where we can get the book from the chapter.
  book: function() {
    return this.belongsTo(Book).through(Chapter);
  }
});

The "through" table creates a pivot model, which it assigns to model.pivot after it is created. On toJSON, the pivot model is flattened to values prefixed with _pivot_.

model.timestamp([options]) → Object source

Parameters
  • [options] Object
    • [method] string

      Either 'insert' or 'update'. Specify what kind of save the attribute update is for.

Returns
Object

A hash of timestamp attributes that were set.

Sets the timestamp attributes on the model, if hasTimestamps is set to true or an array. Check if the model isNew or if {method: 'insert'} is provided as an option and set the created_at and updated_at attributes to the current date if it is being inserted, and just the updated_at attribute if it's being updated. This method may be overriden to use different column names or types for the timestamps.

model.toJSON([options]) source

Parameters

Called automatically by JSON.stringify. To customize serialization, override serialize.

model.trigger() source

Example
ship.trigger('fetched');
See

model.triggerThen(name, [args]) source

Parameters
  • name string

    The event name, or a whitespace-separated list of event names, to be triggered.

  • [args] mixed

    Arguments to be passed to any registered event handlers.

Returns

Promise A promise resolving the the resolved return values of any triggered handlers.

A promise version of Events#trigger, returning a promise which resolves with all return values from triggered event handlers. If any of the event handlers throw an Error or return a rejected promise, the promise will be rejected. Used internally on the "creating", "updating", "saving", and "destroying" events, and can be helpful when needing async event handlers (for validations, etc).

model.unset(attribute)Model source

Parameters
  • attribute

    Attribute to unset.

Returns
Model

This model.

Remove an attribute from the model. unset is a noop if the attribute doesn't exist.

model.where(method)Model source

Example
model.where('favorite_color', '<>', 'green').fetch().then(function() { //...
// or
model.where('favorite_color', 'red').fetch().then(function() { //...
// or
model.where({favorite_color: 'red', shoe_size: 12}).fetch().then(function() { //...
Parameters
  • method Object|string

    Either key, [operator], value syntax, or a hash of attributes to match. Note that these must be formatted as they are in the database, not how they are stored after Model#parse.

See
Returns
Model

Self, this method is chainable.

The where method is used as convenience for the most common query method, adding a where clause to the builder. Any additional knex methods may be accessed using query.

Accepts either key, value syntax, or a hash of attributes.

Lodash Methods

Events

model.on("counting", (model, options) => source

Parameters
  • model Model

    The model firing the event.

  • options Object

    Options object passed to count.

Returns
Promise

Counting event.

Fired before a count query. A promise may be returned from the event handler for async behaviour.

model.on("created", (model, attrs, options) => source

Parameters
  • model Model

    The model firing the event.

  • attrs Object

    Model firing the event.

  • options Object

    Options object passed to save.

Returns
Promise

Created event.

Fired after an insert query.

model.on("creating", (model, attrs, options) => source

Parameters
  • model Model

    The model firing the event.

  • attrs Object

    Attributes that will be inserted.

  • options Object

    Options object passed to save.

Returns
Promise

Creating event.

Fired before insert query. A promise may be returned from the event handler for async behaviour. Throwing an exception from the handler will cancel the save operation.

model.on("destroyed", (model, attrs, options) => source

Parameters
  • model Model

    The model firing the event.

  • attrs Object

    Model firing the event.

  • options Object

    Options object passed to save.

Returns
Promise

Destroyed event.

Fired before a delete query. A promise may be returned from the event handler for async behaviour.

model.on("destroying", (model, options) => source

Parameters
  • model Model

    The model firing the event.

  • options Object

    Options object passed to save.

Returns
Promise

Destroying event.

Fired before a delete query. A promise may be returned from the event handler for async behaviour. Throwing an exception from the handler will reject the promise and cancel the deletion.

model.on("fetched", (model, reponse, options) => source

Parameters
  • model Model

    The model firing the event.

  • reponse Object

    Knex query response.

  • options Object

    Options object passed to fetch.

Returns
Promise

If the handler returns a promise, fetch will wait for it to be resolved.

Fired after a fetch operation. A promise may be returned from the event handler for async behaviour.

model.on("fetching", (model, columns, options) => source

Parameters
  • model Model

    The model which is about to be fetched.

  • columns string[]

    The columns to be retrieved by the query.

  • options Object

    Options object passed to fetch.

    • query QueryBuilder

      Query builder to be used for fetching. This can be modified to change the query before it is executed.

Returns
Promise

Fired before a fetch operation. A promise may be returned from the event handler for async behaviour.

model.on("saved", (model, resp, options) => source

Parameters
  • model Model

    The model firing the event.

  • resp Object

    The database response.

  • options Object

    Options object passed to save.

Returns
Promise

Saved event.

Fired after an insert or update query.

model.on("saving", (model, attrs, options) => source

Parameters
  • model Model

    The model firing the event.

  • attrs Object

    Attributes that will be inserted or updated.

  • options Object

    Options object passed to save.

Returns
Promise

Saving event.

Fired before an insert or update query. A promise may be returned from the event handler for async behaviour. Throwing an exception from the handler will cancel the save.

model.on("updated", (model, attrs, options) => source

Parameters
  • model Model

    The model firing the event.

  • attrs Object

    Model firing the event.

  • options Object

    Options object passed to save.

Returns
Promise

Updated event.

Fired after an update query.

model.on("updating", (model, attrs, options) => source

Parameters
  • model Model

    The model firing the event.

  • attrs Object

    Attributes that will be updated.

  • options Object

    Options object passed to save.

Returns
Promise

Updating event.

Fired before update query. A promise may be returned from the event handler for async behaviour. Throwing an exception from the handler will cancel the save operation.

Model.NoRowsDeletedError

Model.NoRowsUpdatedError

Construction

new Model.NoRowsUpdatedError() source

Thrown when no records are saved by save unless called with the {require: false} option.

Model.NotFoundError

Collection

Collections are ordered sets of models returned from the database, from a fetchAll call. They may be used with a suite of Lodash methods.

Construction

new Collection([models], [options]) source

Example
let tabs = new TabSet([tab1, tab2, tab3]);
Parameters
  • [models] Model[]

    Initial array of models.

  • [options] Object
    • [comparator=false] bool

      Comparator for collection, or false to disable sorting.

When creating a Collection, you may choose to pass in the initial array of models. The collection's comparator may be included as an option. Passing false as the comparator option will prevent sorting. If you define an initialize function, it will be invoked when the collection is created.

collection.initialize() source

Custom initialization function.

Static

Collection.extend([prototypeProperties], [classProperties]) → function source

Parameters
  • [prototypeProperties] Object

    Instance methods and properties to be attached to instances of the new class.

  • [classProperties] Object

    Class (ie. static) functions and properties to be attached to the constructor of the new class.

Returns
function

Constructor for new Collection subclass.

To create a Collection class of your own, extend Bookshelf.Collection.

Collection.forge([models], options) source

Example
var Promise = require('bluebird');
var Accounts = bookshelf.Collection.extend({
  model: Account
});

var accounts = Accounts.forge([
  {name: 'Person1'},
  {name: 'Person2'}
]);

Promise.all(accounts.invoke('save')).then(function() {
  // collection models should now be saved...
});
Parameters
  • [models] Object[]|Model[]

    Set of models (or attribute hashes) with which to initialize the collection.

  • options Object

    Hash of options.

A simple helper function to instantiate a new Collection without needing new.

Methods

collection.add(models, [options])Collection source

Example
const ships = new bookshelf.Collection;

ships.add([
  {name: "Flying Dutchman"},
  {name: "Black Pearl"}
]);
Parameters
  • models Object[]|Model[]|Object|Model

    One or more models or raw attribute objects.

  • [options] Object

    See description.

Returns
Collection

Self, this method is chainable.

Add a model (or an array of models) to the collection, You may also pass raw attributes objects, and have them be vivified as instances of the model. Pass {at: index} to splice the model into the collection at the specified index. If you're adding models to the collection that are already in the collection, they'll be ignored, unless you pass {merge: true}, in which case their attributes will be merged into the corresponding models.

Note that adding the same model (a model with the same id) to a collection more than once is a no-op.

collection.at() source

Get a model from a collection, specified by index. Useful if your collection is sorted, and if your collection isn't sorted, at will still retrieve models in insertion order.

collection.attach(ids, options) → Promise<Collection> source

Parameters
  • ids mixed|mixed[]

    One or more ID values or models to be attached to the relation.

  • options Object

    A hash of options.

    • transacting Transaction

      Optionally run the query in a transaction.

Returns
Promise<Collection>

A promise resolving to the updated Collection.

Attaches one or more ids or models from a foreign table to the current table, on a many-to-many relation. Creates and saves a new model and attaches the model with the related model.

var admin1 = new Admin({username: 'user1', password: 'test'});
var admin2 = new Admin({username: 'user2', password: 'test'});

Promise.all([admin1.save(), admin2.save()])
  .then(function() {
    return Promise.all([
    new Site({id: 1}).admins().attach([admin1, admin2]),
    new Site({id: 2}).admins().attach(admin2)
  ]);
})

This method (along with Collection#detach and Collection#updatePivot) are mixed in to a Collection when returned by a belongsToMany relation.

collection.clone() source

Create a new collection with an identical list of models as this one.

collection.count([column], [options]) → Promise source

Example
// select count(*) from shareholders where company_id = 1 and share &gt; 0.1;
Company.forge({id:1})
  .shareholders()
  .query('where', 'share', '>', '0.1')
  .count()
  .then(function(count) {
    assert(count === 3);
  });
Parameters
  • [column='*'] string

    Specify a column to count - rows with null values in this column will be excluded.

  • [options] Object

    Hash of options.

Since
  • 0.8.2
Returns
Promise

A promise resolving to the number of matching rows.

Get the number of records in the collection's table.

collection.create(model, [options]) → Promise<Model> source

Parameters
  • model Object

    A set of attributes to be set on the new model.

  • [options] Object
    • [transacting] Transaction
Returns
Promise<Model>

A promise resolving with the new model.

Convenience method to create a new model instance within a collection. Equivalent to instantiating a model with a hash of attributes, saving the model to the database then adding the model to the collection.

When used on a relation, create will automatically set foreign key attributes before persisting the Model.

const { courses, ...attributes } = req.body;

Student.forge(attributes).save().tap(student =>
  Promise.map(courses, course => student.related('courses').create(course))
).then(student =>
  res.status(200).send(student)
).catch(error =>
  res.status(500).send(error.message)
);

collection.detach([ids], options) → Promise source

Parameters
  • [ids] mixed|mixed[]

    One or more ID values or models to be detached from the relation.

  • options Object

    A hash of options.

    • transacting Transaction

      Optionally run the query in a transaction.

Returns
Promise

A promise resolving to undefined.

Detach one or more related objects from their pivot tables. If a model or id is passed, it attempts to remove the pivot table based on that foreign key. If no parameters are specified, we assume we will detach all related associations.

This method (along with Collection#attach and Collection#updatePivot) are mixed in to a Collection when returned by a belongsToMany relation.

collection.fetch([options]) → Promise<Collection> source

Parameters
  • [options] Object
    • [require=false] bool

      Trigger a Collection.EmptyError if no records are found.

    • [withRelated=[]] string|string[]

      A relation, or list of relations, to be eager loaded as part of the fetch operation.

Fires
Throws
Collection.EmptyError

Upon a sucessful query resulting in no records returns. Only fired if require: true is passed as an option.

Returns
Promise<Collection>

Fetch the default set of models for this collection from the database, resetting the collection when they arrive. If you wish to trigger an error if the fetched collection is empty, pass {require: true} as one of the options to the fetch call. A "fetched" event will be fired when records are successfully retrieved. If you need to constrain the query performed by fetch, you can call the query method before calling fetch.

If you'd like to only fetch specific columns, you may specify a columns property in the options for the fetch call.

The withRelated option may be specified to fetch the models of the collection, eager loading any specified relations named on the model. A single property, or an array of properties can be specified as a value for the withRelated property. The results of these relation queries will be loaded into a relations property on the respective models, may be retrieved with the related method.

collection.fetchOne([options]) → Promise<Model|null> source

Example
// select * from authors where site_id = 1 and id = 2 limit 1;
new Site({id:1})
  .authors()
  .query({where: {id: 2}})
  .fetchOne()
  .then(function(model) {
    // ...
  });
Parameters
  • [options] Object
    • [require=false] boolean

      If true, will reject the returned response with a NotFoundError if no result is found.

    • [columns='*'] string|string[]

      Limit the number of columns fetched.

    • transacting Transaction

      Optionally run the query in a transaction.

Throws
Model.NotFoundError
Returns
Promise<Model|null>

A promise resolving to the fetched model or null if none exists.

Fetch and return a single model from the collection, maintaining any relation data from the collection, and any query parameters that have already been passed to the collection. Especially helpful on relations, where you would only like to return a single model from the associated collection.

collection.findWhere()Model source

Returns
Model

The first matching model.

Return the first model with matching attributes. Useful for simple cases of find.

collection.get()Model source

Example
const book = library.get(110);
Returns
Model

The model, or undefined if it is not in the collection.

Get a model from a collection, specified by an id, a cid, or by passing in a model.

collection.invokeThen(method, arguments) → Promise source

Parameters
  • method string

    The model method to invoke.

  • arguments mixed

    Arguments to method.

Returns
Promise

Promise resolving to array of results from invocation.

Shortcut for calling Promise.all around a Collection#invoke, this will delegate to the collection's invoke method, resolving the promise with an array of responses all async (and sync) behavior has settled. Useful for bulk saving or deleting models:

collection.invokeThen('save', null, options).then(function() {
  // ... all models in the collection have been saved
});

collection.invokeThen('destroy', options).then(function() {
  // ... all models in the collection have been destroyed
});

collection.load(relations, [options]) → Promise<Collection> source

Parameters
  • relations string|string[]

    The relation, or relations, to be loaded.

  • [options] Object

    Hash of options.

    • [transacting] Transaction
Returns
Promise<Collection>

A promise resolving to this collection

load is used to eager load relations onto a Collection, in a similar way that the withRelated property works on fetch. Nested eager loads can be specified by separating the nested relations with '.'.

collection.off() source

Example
ships.off('fetched') // Remove the 'fetched' event listener
See

collection.on() source

Example
const ships = new bookshelf.Collection;
ships.on('fetched', function(collection, response) {
  // Do something after the data has been fetched from the database
})
See

collection.once(nameOrNames, callback) source

Parameters
  • nameOrNames string

    The name of the event or space separated list of events to register a callback for.

  • callback function

    That callback to invoke only once when the event is fired.

Just like Events#on, but causes the bound callback to fire only once before being removed. Handy for saying "the next time that X happens, do this". When multiple events are passed in using the space separated syntax, the event will fire once for every event you passed in, not once for a combination of all events.

collection.orderBy(sort, order) source

Example
Cars.forge().orderBy('color', 'ASC').fetch()
   .then(function (rows) { // ...
Parameters
  • sort string

    Column to sort on

  • order string

    Ascending ('ASC') or descending ('DESC') order

Since
  • 0.9.3

Specifies the column to sort on and sort order.

The order parameter is optional, and defaults to 'ASC'. You may also specify 'DESC' order by prepending a hyphen to the sort column name. orderBy("date", 'DESC') is the same as orderBy("-date").

Unless specified using dot notation (i.e., "table.column"), the default table will be the table name of the model orderBy was called on.

collection.parse(resp) source

Parameters
  • resp Object[]

    Raw database response array.

The parse method is called whenever a collection's data is returned in a fetch call. The function is passed the raw database response array, and should return an array to be set on the collection. The default implementation is a no-op, simply passing through the JSON response.

collection.pluck() → mixed[] source

Returns
mixed[]

An array of attribute values.

Pluck an attribute from each model in the collection.

collection.pop() source

Remove a model from the end of the collection.

collection.push(model)Collection source

Parameters
  • model Object[]|Model[]|Object|Model

    One or more models or raw attribute objects.

Returns
Collection

Self, this method is chainable.

Add a model to the end of the collection.

collection.query(arguments)Collection|QueryBuilder source

Example
let qb = collection.query();
    qb.where({id: 1}).select().then(function(resp) {
      // ...
    });

collection.query(function(qb) {
  qb.where('id', '>', 5).andWhere('first_name', '=', 'Test');
}).fetch()
  .then(function(collection) {
    // ...
  });

collection
  .query('where', 'other_id', '=', '5')
  .fetch()
  .then(function(collection) {
    // ...
  });
Parameters
  • arguments function|Object|string

    The query method.

See
Returns
Collection|QueryBuilder

Will return this model or, if called with no arguments, the underlying query builder.

query is used to tap into the underlying Knex query builder instance for the current collection. If called with no arguments, it will return the query builder directly. Otherwise, it will call the specified method on the query builder, applying any additional arguments from the collection.query call. If the method argument is a function, it will be called with the Knex query builder as the context and the first argument.

collection.reduceThen(iterator, initialValue, context) → Promise source

Parameters
  • iterator function
  • initialValue mixed
  • context Object

    Bound to this in the iterator callback.

See
Returns
Promise

Promise resolving to array of results from invocation.

Run "reduce" over the models in the collection.

collection.remove(models, options)Model|Model[] source

Parameters
  • models Model|Model[]

    The model, or models, to be removed.

  • options Object
Returns
Model|Model[]

The same value passed as models argument.

Remove a model (or an array of models) from the collection, but does not remove the model from the database, use the model's destroy method for this.

collection.reset(models, options)Model[] source

Parameters
  • models Object[]|Model[]|Object|Model

    One or more models or raw attribute objects.

  • options Object

    See add.

Returns
Model[]

Array of models.

Adding and removing models one at a time is all well and good, but sometimes you have so many models to change that you'd rather just update the collection in bulk. Use reset to replace a collection with a new list of models (or attribute hashes). Calling collection.reset() without passing any models as arguments will empty the entire collection.

collection.resetQuery()Collection source

Returns
Collection

Self, this method is chainable.

Used to reset the internal state of the current query builder instance. This method is called internally each time a database action is completed by Sync.

collection.serialize([options]) → Object source

Parameters
  • [options] Object
    • [shallow=false] bool

      Exclude relations.

    • [omitPivot=false] bool

      Exclude pivot values.

    • [omitNew=false] bool

      Exclude models that return true for isNew.

Returns
Object

Serialized model as a plain object.

Return a raw array of the collection's attributes for JSON stringification. If the models have any relations defined, this will also call toJSON on each of the related objects, and include them on the object unless {shallow: true} is passed as an option.

serialize is called internally by toJSON. Override this function if you want to customize its output.

collection.set(models, [options])Collection source

Example
var vanHalen = new bookshelf.Collection([eddie, alex, stone, roth]);
vanHalen.set([eddie, alex, stone, hagar]);
Parameters
  • models Object[]|Model[]|Object|Model

    One or more models or raw attribute objects.

  • [options] Object

    See description.

Returns
Collection

Self, this method is chainable.

The set method performs a "smart" update of the collection with the passed model or list of models. If a model in the list isn't yet in the collection it will be added; if the model is already in the collection its attributes will be merged; and if the collection contains any models that aren't present in the list, they'll be removed. If you'd like to customize the behavior, you can disable it with options: {add: false}, {remove: false}, or {merge: false}.

collection.shift() source

Remove a model from the beginning of the collection.

collection.slice() source

Slice out a sub-array of models from the collection.

collection.through() source

Used to define passthrough relationships - hasOne, hasMany, belongsTo or belongsToMany, "through" an Interim model or collection.

collection.toJSON(Options) source

Parameters

Called automatically by JSON.stringify. To customize serialization, override serialize.

collection.trigger() source

Example
ships.trigger('fetched')
See

collection.triggerThen(name, [args]) source

Parameters
  • name string

    The event name, or a whitespace-separated list of event names, to be triggered.

  • [args] mixed

    Arguments to be passed to any registered event handlers.

Returns

Promise A promise resolving the the resolved return values of any triggered handlers.

A promise version of Events#trigger, returning a promise which resolves with all return values from triggered event handlers. If any of the event handlers throw an Error or return a rejected promise, the promise will be rejected. Used internally on the "creating", "updating", "saving", and "destroying" events, and can be helpful when needing async event handlers (for validations, etc).

collection.unshift() source

Add a model to the beginning of the collection.

collection.updatePivot(attributes, [options]) → Promise source

Parameters
  • attributes Object

    Values to be set in the update query.

  • [options] Object

    A hash of options.

    • [query] function|Object

      Constrain the update query. Similar to the method argument to Model#query.

    • [require=false] bool

      Causes promise to be rejected with an Error if no rows were updated.

    • [transacting] Transaction

      Optionally run the query in a transaction.

Returns
Promise

A promise resolving to number of rows updated.

The updatePivot method is used exclusively on belongsToMany relations, and allows for updating pivot rows on the joining table.

This method (along with Collection#attach and Collection#detach) are mixed in to a Collection when returned by a belongsToMany relation.

collection.where()Model[] source

Returns
Model[]

Array of matching models.

Return models with matching attributes. Useful for simple cases of filter.

collection.withPivot(columns)Collection source

Parameters
  • columns string[]

    Names of columns to be included when retrieving pivot table rows.

Returns
Collection

Self, this method is chainable.

The withPivot method is used exclusively on belongsToMany relations, and allows for additional fields to be pulled from the joining table.

var Tag = bookshelf.Model.extend({
  comments: function() {
    return this.belongsToMany(Comment).withPivot(['created_at', 'order']);
  }
});

Lodash Methods

Events

collection.on("fetched", (collection, reponse, options) => source

Parameters
Returns
Promise

Fired after a fetch operation. A promise may be returned from the event handler for async behaviour.

Collection.EmptyError

Events

Construction

new Events() source

Base Event class inherited by Model and Collection. It's not meant to be used directly, and is only displayed here for completeness.

Methods

events.off(nameOrNames) source

Parameters
  • nameOrNames string

    The name of the event or space separated list of events to stop listening to.

Remove a previously-bound callback event listener from an object. If no event name is specified, callbacks for all events will be removed.

events.on(nameOrNames, callback) source

Parameters
  • nameOrNames string

    The name of the event or space separated list of events to register a callback for.

  • callback function

    That callback to invoke whenever the event is fired.

Register an event listener. The callback will be invoked whenever the event is fired. The event string may also be a space-delimited list of several event names.

events.once(nameOrNames, callback) source

Parameters
  • nameOrNames string

    The name of the event or space separated list of events to register a callback for.

  • callback function

    That callback to invoke only once when the event is fired.

Just like Events#on, but causes the bound callback to fire only once before being removed. Handy for saying "the next time that X happens, do this". When multiple events are passed in using the space separated syntax, the event will fire once for every event you passed in, not once for a combination of all events.

events.trigger(nameOrNames, [args]) source

Parameters
  • nameOrNames string

    The name of the event to trigger. Also accepts a space separated list of event names.

  • [args] mixed

    Extra arguments to pass to the event listener callback function.

Trigger callbacks for the given event, or space-delimited list of events. Subsequent arguments to trigger will be passed along to the event callback.

events.triggerThen(name, [args]) source

Parameters
  • name string

    The event name, or a whitespace-separated list of event names, to be triggered.

  • [args] mixed

    Arguments to be passed to any registered event handlers.

Returns

Promise A promise resolving the the resolved return values of any triggered handlers.

A promise version of Events#trigger, returning a promise which resolves with all return values from triggered event handlers. If any of the event handlers throw an Error or return a rejected promise, the promise will be rejected. Used internally on the "creating", "updating", "saving", and "destroying" events, and can be helpful when needing async event handlers (for validations, etc).

Change Log

0.10.2 - Sept 22, 2016_Diff

  • Fixes memory leak introduced in 0.10.0 caused by binding this.listeners in triggerThen
  • Fixes Bluebird warning when a Promise was internally rejected with a non-error

0.10.1 - Sept 14, 2016Diff

  • Allows using knex 0.12 as a peerDependency
  • knex instance used by bookshelf may be swapped out

0.10.0Jun 29, 2016Diff

Breaking Changes:

  • Removal/renaming of certain lodash functions from Model and Collection that were removed in lodash 4.
    • Collection Methods
      • removed CollectionBase#collect => use CollectionBase#map instead
      • removed CollectionBase#foldl => use CollectionBase#reduce instead
      • removed CollectionBase#inject => use CollectionBase#reduce instead
      • removed CollectionBase#foldr => use CollectionBase#reduceRight instead
      • removed CollectionBase#detect => use CollectionBase#find instead
      • removed CollectionBase#select => use CollectionBase#filter instead
      • removed CollectionBase#all => use CollectionBase#every instead
      • removed CollectionBase#any => use CollectionBase#some instead
      • removed CollectionBase#include => use CollectionBase#includes instead
      • removed CollectionBase#contains => use CollectionBase#includes instead
      • removed CollectionBase#rest => use CollectionBase#tail instead
      • renamed CollectionBase#invoke => CollectionBase#invokeMap
      • split CollectionBase#max into CollectionBase#maxBy - see the lodash docs for more explanation
      • split CollectionBase#min into CollectionBase#minBy - see the lodash docs for more explanation
    • Model Methods
      • renamed ModelBase#pairs => ModelBase#toPairs

Other Changes:

  • Update to Lodash 4. #1287
  • Registry plugin: Better support for custom relations. #1294

0.9.5May 15, 2016Diff

  • Add pagination plugin. #1183
  • Fire Model#event:fetched on eagerly loaded relations. #1206
  • Correct cloning of Model#belongsToMany decorated relations. #1222
  • Update Knex to 0.11.x. #1227
  • Update minimum lodash version. #1230

0.9.4April 3, 2016Diff

  • Include babel-runtime as a dependency. #1188

0.9.3April 3, 2016Diff

  • Bugfix: Restore support for camelCase and color:separated event names. #1184

0.9.2February 17, 2016Diff

  • Permit up to Knex 0.11.0 via peerDependencies.
  • Model.forge works for ES6 classes. #924
  • Fix Collection#count for hasMany relations. #1115

0.9.1November 4, 2015Diff

  • Events#off can now deregister multiple methods at once. #983
  • Permit Knex 0.10.0 via peerDependencies. #998

0.9.0November 1, 2015Diff

  • Repo no longer includes built source or generated documentation. Release script updated to include these only in the tagged release commit. #950.
  • Model#previous returned undefined instead of null for non-existant attributes.
  • Update tests and documentation to confirm that null (rather than undefined) is returned from Model#fetch and Collection#fetchOne.
  • Fix error in virtual plugin - #936
  • Correct error updating parsed/formatted Model#idAttribute after successful insert operation. #955
  • Many documentation fixes.

0.8.2August 20, 2015Diff

  • ES6/7: Move code base to /src — code is now compiled into /lib via Babel.
  • Add collection.count, model.count and Model.count.
  • Add model.refresh. #796
  • Prevent fetch and refresh from trying to add JSON attributes to a where clause. #550 #778
  • Virtuals plugin now supports {patch: true} argument to model.save. #542
  • Restored model.clone and collection.clone, which were not previously working. #744
  • Allow bookshelf.Collection to be modified and extended by plugins (so that relations and fetchAll operations will return the extended instance). #681 #688
  • Fix model.timestamps behaviour which deviated from documentation. Also ensure that createdAt is set when {method: "insert"} is passed explicitly. #787
  • Calling create on a through relationship no longer tries to make a pivot object. Previously this would attempt to create an object with invalid foreign keys. #768
  • Parse foreign keys set during create in a relation. #770

0.8.1May 12, 2015Diff

  • Fix for regression in initialize not being called in Collection constructor, #737.
  • Fix for regression, removing omitPivot in 0.8 #721
  • Added serialize, a method which contains toJSON logic for easier customization.

0.8.0May 1, 2015Diff

  • Dropped Backbone dependency
  • More specific errors throughout, #522
  • Support {require: true} for model.destroy #617
  • Add lifecycle events on pivot models for belongsToMany, .through #578
  • Allows for select/column calls in the query builder closure, #633.
  • Added per-constructor error classes #694 (note: this will not work in CoffeeScript).

Breaking Changes:

  • Removed the __super__ internal property on the constructor, this shouldn't have been something you were relying on anyway.

0.7.9Oct 28, 2014Diff

  • Fix for regression in columns / eager fetch query constraints, (#510).

0.7.8Oct 28, 2014Diff

  • Timestamp created_at is now saved with any insert.
  • Fix for regression created by #429.
  • New events, attaching, attached, detaching, detached #452.
  • Ability to specify custom column names in morphTo, #454
  • Fix for stack overflow with model list as arguments, #482
  • Modified location of eager fetch query constraints internally.

0.7.7July 23, 2014Diff

  • Fix for formatting on polymorphic keys, (#429).
  • Added a resolve method for specifying a custom resolver function for the registry plugin.

0.7.6June 29, 2014Diff Add omitPivot flag on toJSON options for omitting the _pivot_ keys in through and belongsToMany relations (#404).

0.7.5June 23, 2014Diff Fix missing NotFoundError & EmptyError on Model & Collection, respectively (#389, 399).

0.7.4June 18, 2014Diff Added bookshelf.model(name, protoProps, [staticProps]) syntax for registry plugin.

0.7.3June 17, 2014Diff Fix for collection dropping models early in set, #376.

0.7.2June 12, 2014Diff Pass a cloned copy of the model's attributes to format rather than the original, related to #315.

0.7.1June 10, 2014Diff Ensure the knex version >= 0.6.10, where a major regression affecting column names was fixed.

0.7.0June 9, 2014

  • Added Model#fetchAll, for fetching a collection of models from a model.
  • Added Model#where, as a shortcut for the most commonly used query method.
  • Initializing via a plain options object is deprecated, you must now pass in an initialized knex instance.
  • Adding typed errors (#221).
  • Upgrade to support knex 0.6.x

0.6.12June 5, 2014Diff Fix for eager loaded belongsTo relation bug with custom parse/format (#377).

0.6.11June 4, 2014Diff Temporarily add knex to peerDependencies until 0.7 is released to support knex 0.6 and there exists a better internal method of doing a semver check. Fix for belongsTo relation bug (#353).

0.6.10April 3, 2014Diff

  • Bumping dependencies, including upgrading to Bluebird 1.2, trigger-then 0.3, fixing an erroneous "unhandledRejection" (#310).
  • fetchOne properly resets the query on the collection, (#300).

0.6.9April 3, 2014Diff Only prefix model fields with the "tableName" after format has been called, (#308).

0.6.8March 6, 2014Diff

  • Virtuals plugin may now accept a hash of attributes to set.
  • Properly fix issue addressed in 0.6.7.

0.6.7March 2, 2014Diff Bugfix for edge case for eager loaded relations and relatedData settings.

0.6.6March 1, 2014Diff Bugfix for registry plugin, resolving correct models for "through" relations. (#260)

0.6.5February 28, 2014Diff

  • Added Collection#reduceThen as a passthrough to Bluebird's "reduce" method with models.
  • Options are now passed to "plugin" method. (#254)
  • Bugfix for registry plugin. (#259)

0.6.4February 11, 2014Diff Adds static method Model.collection() as a shortcut for creating a collection with the current model.

0.6.3February 9, 2014Diff

  • Added anRelation#updatePivot method for updating tables on a "belongsToMany" relation. (#134, #230)
  • Allow mutating the options for passing constraints to eager loaded relations. (#151)
  • All keys of an object passed into sync are properly prefixed before sync. (#177)
  • Clearer error messages for debugging. (#204, #197)
  • Fixed error message for updates that don't affect rows. (#228)
  • Group by the correct key on "belongsTo.through" relations. (#214)
  • Ability to only use created_at or updated_at as timestamp properties. (#158)
  • Numerous documentation corrections, clarifications, enhancements.
  • Bumped Bluebird dependency to ~1.0.0.

Plugins:

  • Added the registry plugin for registering models as strings, helping with the circular dependency problem
  • Added the virtuals plugin for getting/setting virtual (computed) properties on the model.
  • Added the visibility plugin for specifying a whitelist/blacklist of keys when a model is serialized with toJSON.

0.6.2December 18, 2013Diff

  • Debug may now be passed as an option in any sync method, to log queries, including relations.
  • Save now triggers an error in updates with no affected rows. (#119)
  • The model.id attribute is only set on insert if it's empty. (#130)
  • Ensure eager loaded relations can use attach/detach. (#120)

0.6.1November 26, 2013Diff Fixes bug with promise code and saving event firing, where promises are not properly resolved with ".all" during saving events.

0.6.0November 25, 2013Diff

  • Updating dependency to knex.js 0.5.x
  • Switched from when.js to bluebird for promise implementation, with shim for backward compatibility.
  • Switched from underscore to lodash, for semver reliability.

0.5.8November 24, 2013Diff

  • Parse models after all relations have been eager loaded, for appropriate column name matching (thanks @benesch) (#97)
  • Specify table for withRelated fetches to prevent column naming conflicts (#96).
  • Fix for polymorphic relation loading (#95).
  • Other documentation tweaks and other internal code cleanup.

0.5.7October 11, 2013Diff The "fetching" event is now fired on eager loaded relation fetches.

0.5.6October 10, 2013Diff The options.query now contains the appropriate knex instance during the "fetching" event handler.

0.5.5October 1, 2013Diff An eager loaded morphTo relation may now have child relations nested beneath it that are properly eager loaded, depending on the parent.

0.5.4October 1, 2013Diff

  • Fix issue where the relatedData context was not appropriately maintained for subsequent Collection#create calls after an eager load (#77).
  • Documentation improvements, encouraging the use of Model#related rather than calling a relation method directly, to keep association with the parent model's relations hash.

0.5.3September 26, 2013Diff The columns explicitly specified in a fetch are no-longer passed along when eager loading relations, fixes (#70).

0.5.2September 22, 2013Diff Fixed incorrect eager loading in belongsTo relations (#65).

0.5.1September 21, 2013Diff Fixed incorrect eager loading in hasOne relations (#63).

0.5.0September 20, 2013Diff Major Breaking Changes:

  • Global state is no longer stored in the library, an instance is returned from Bookshelf.initialize, so you will need to call this once and then reference this Bookshelf client elsewhere in your application.
  • Lowercasing of bookshelf.initialize, bookshelf.knex, bookshelf.transaction.
  • During the lifecycle events, such as "fetching", "saving", or "destroying", the model no-longer contains the active query builder instance at the time it is saved. If you need to modify the query builder chain inside of an event handler, you may now use options.query inside the event handlers.

Other Changes:

  • Added tableName for all queries, so joins use the correct id (#61).
  • The attach & detach now remove models from the associated collection, as appropriate (#59).
  • A withPivot no longer accepts an object to specify the keys for the returned pivot items, if you wish to specify how these pivot objects are defined on the object, a custom toJSON is your best bet.
  • Added Collection#invokeThen and Collection#mapThen as convenience helpers for Promise.all(collection.invoke(method, args*)) and Promise.all(collection.map(method, iterator, [context])), respectively.
  • Added a Bookshelf.plugin method, for a standard way to extend Bookshelf instances.
  • A re-written modular architecture, to move the library toward becoming a database agnostic "data mapper" foundation, with the ablitiy to form relations between different data stores and types, not just SQL (although SQL is the primary focus for now). Also, support for AMD, for eventual use outside of Node.js runtime (with webSQL and likewise).

0.3.1August 29, 2013DiffDocs Fixed regression in belongsToMany custom column name order.

0.3.0August 28, 2013 Support for a Model#through clause on various model relations. Creating a model from a related collection maintains the appropriate relation data (#35). Support for a {patch: true} flag on save, to only update specific saved attributes. Added a fetchOne method, for pulling out a single model from a collection, mostly useful for related collection instances. Updated to Knex "0.2.x" syntax for insert / returning, Ability to specify a morphValue on Model#morphOne or Model#morphMany relations. Internal refactor of relations for more consistent behavior.

0.2.8August 26, 2013 Some minor fixes to make the Sync methods more consistent in their behavior when called directly, (#53).

0.2.7August 21, 2013 Timestamp for created_at is not set during an "update" query, and the update where clause does not include the idAttribute if it isn't present (#51).

0.2.6August 21, 2013 Fixes bug with query function feature added in 0.2.5, mentioned in (#51).

0.2.5August 19, 2013 The Model#query method may now accept a function, for even more dynamic query building (#45). Fix for relations not allowing "0" as a valid foreign key value (#49).

0.2.4July 30, 2013 More consistent query resetting, fixing query issues on post-query event handlers. The toJSON is only called on a related model if the method exists, allowing for objects or arrays to be manually specified on the relations hash and serialized properly on the parent's toJSON.

0.2.3July 7, 2013 Fixing bug where triggerThen wasn't actually being used for several of the events as noted in 0.2.1 release.

0.2.2July 2, 2013 The Model's related method is now a no-op if the model doesn't have the related method. Any withPivot columns on many-to-many relations are now prefixed with _pivot rather than pivot unless named otherwise, for consistency. The _reset is not called until after all triggered events so that hasChanged can be used on the current model state in the "created", "updated", "saved", and "destroyed" events. Eager queries may be specified as an object with a function, to constrain the eager queries:

user.fetch({withRelated: ['accounts', {
'accounts.settings': function(qb) { qb.where('status', 'enabled'); }
}, 'other_data']}).then(...

0.2.1June 26, 2013 Using triggerThen instead of trigger for "created", "updated", "saved", "destroyed", and "fetched" events - if any async operations are needed after the model is created but before resolving the original promise.

0.2.0June 24, 2013 Resolve Model's fetch promise with null rather than undefined. An object of query. constraints (e.g. {where: {...}, orWhere: {...}}may be passed to the query method (#30). Fix for empty eager relation responses not providing an empty model or collection instance on the model.relations object.

0.1.9June 19, 2013 Resolve Model's fetch promise with undefined if no model was returned. An array of "created at" and "updated at" values may be used for hasTimestamps. Format is called on the Model#fetch method. Added an exec plugin to provide a node callback style interface for any of the promise methods.

0.1.8June 18, 2013 Added support for polymorphic associations, with morphOne, morphMany, and morphTo model methods.

0.1.7June 15, 2013 Bugfix where detach may be used with no parameters to detach all related items (#19).

0.1.6June 15, 2013 Fixing bug allowing custom idAttribute values to be used in eager loaded many-to-many relations (#18).

0.1.5June 11, 2013 Ensuring each of the _previousAttribute and changed values are properly reset on related models after sync actions.

0.1.4June 10, 2013 Fixing issue with idAttribute not being assigned after database inserts. Removing various aliases Events methods for clarity.

0.1.3June 10, 2013 Added Model#hasChanged, Model#previous, and Model#previousAttributes methods, for getting the previous value of the model since the last sync. Using Object.create(null) for various internal model objects dealing with user values. Calling Model#related on a model will now create an empty related object if one is not present on the relations object. Removed the {patch: true} option on save, instead only applying defaults if the object isNew, or if {defaults: true} is passed. Fix for model.clone's relation responses.

0.1.2May 17, 2013 Added triggerThen and emitThen for promise based events, used internally in the "creating", "updating", "saving", and "destroying" events. Docs updates, fixing {patch: true} on update to have intended functionality. A model's toJSON is now correctly called on any related properties.

0.1.1May 16, 2013 Fixed bug with eager loaded belongsTo relations (#14).

0.1.0May 13, 2013 Initial Bookshelf release.