Search code examples
javascriptrdbmsknex.jsbookshelf.js

Querying with Bookshelf


I recently started using Bookshelf. Examples in the documentation aren't very clear to me. This is one such example:

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);
});

After the creation of three models (User, Posts, and Tag) - there is a query.

  1. What exactly is the meaning of this query?

    User.where('id', 1).fetch({withRelated: ['posts.tags']}).then(function(user) {
      console.log(user.related('posts').toJSON());
    }).catch(function(err) {
      console.error(err);
    });
    
  2. What are withRelated, 'posts.tags', user.related('posts')? Can anyone tell me in simplest form, what those terms are and where they come from?

  3. Finally, what is the meaning of the complete query?


Solution

  • It's all answered in the documentation, although not everything in the exact same place, so I can understand your confusion. You really have to read the whole thing to better understand it.

    From the documentation of Model.fetch():

    withRelated: Relations to be retrieved with Model instance. Either one or more relation names (...) A single property, or an array of properties can be specified as a value for the withRelated property.

    From Collection.fetch():

    The withRelated option may be specified to fetch the models of the collection, eager loading any specified relations named on the model.

    From Collection.load():

    ... Nested eager loads can be specified by separating the nested relations with .

    From Model.related():

    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.

    All of these are involved in the eager loading of relations on models.

    What these methods do is load some data from a table that is related to the parent model's table in some way. In the example you posted, the User model has some Posts and the Posts themselves have some tags, so the relations go something like:

    User
      |_ Post
           |_ Tag
    

    These are expressed as methods on each model, for example, posts: function() { ... } in the User model.

    When you specify a relation to eager load using withRelated, you use these method names. Furthermore you can eager load deeply nested relations by separating them with a ., and that's what you're seeing in the example.

    So, putting everything together what that example is doing is searching for the User with id = 1 and also retrieving all the posts that belong to that user as well as all the tags that belong to all the posts that belong to the user.

    Then to access these related objects you use the related('something') method of the model.