sadrzadehsina
sadrzadehsina

Reputation: 1349

model.fetch with related models bookshelfjs

I have below models

company.js

var Company = DB.Model.extend({
  tableName: 'company',
  hasTimestamps: true,
  hasTimestamps: ['created_at', 'updated_at']
});

user.js

var User = DB.Model.extend({
  tableName: 'user',
  hasTimestamps: true,
  hasTimestamps: ['created_at', 'updated_at'],
  companies: function() {
    return this.belongsToMany(Company);
  }
});

With a many-to-many relation between Company and User which handle via the following table in the database.

user_company.js

var UserCompany = DB.Model.extend({
  tableName: 'user_company',
  hasTimestamps: true,
  hasTimestamps: ['created_at', 'updated_at'],
  users: function() {
    return this.belongsToMany(User);
  },
  companies: function() {
    return this.belongsToMany(Company);
  }
});

The problem is when I run following query.

var user = new User({ id: req.params.id });
user.fetch({withRelated: ['companies']}).then(function( user ) {
  console.log(user);
}).catch(function( error ) {
  console.log(error);
});

It logs following error because it is looking for company_user table instead of user_company.

{ [Error: select `company`.*, `company_user`.`user_id` as `_pivot_user_id`, `company_user`.`company_id` as `_pivot_company_id` from `company` inner join `company_user` on `company_user`.`company_id` = `company`.`id` where `company_user`.`user_id` in (2) - ER_NO_SUCH_TABLE: Table 'navardeboon.company_user' doesn't exist]
code: 'ER_NO_SUCH_TABLE',
errno: 1146,
sqlState: '42S02',
index: 0 }

Is there any way to tell it to look for a certain table while fetching relations?

Upvotes: 2

Views: 1060

Answers (2)

sadrzadehsina
sadrzadehsina

Reputation: 1349

Actually I found a very simple solution for it. You just need to mention table name like this:

var User = DB.Model.extend({
  tableName: 'user',
  hasTimestamps: true,
  hasTimestamps: ['created_at', 'updated_at'],
  companies: function() {
   return this.belongsToMany(Company, **'user_company'**);
  }
})

and as @uglycode said, no need to have UserCompany model anymore.

Upvotes: 0

uglycode
uglycode

Reputation: 3082

With Bookshelf.js it is VERY important, how the tables and ids are named in your database. Bookshelf.js does some interesting things with foreign keys (i.e. converts it to singular and appends _id).

When using Bookshelfjs's many-to-many feature, you don't need UserCompany model. However, you need to following the naming conventions of the tables and ids for this to work.

Here's an example of many-to-many models. Firstly, the database:

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

Please note how the junction table is named: alphabetically ordered (authors_books). If you'd write books_authors, the many-to-many features wouldn't work out of the box (you'd have to specify the table name explicitly in the model). Also note the foreign keys (singular of authors with _id appended, i.e. author_id).

Now let's look at the models.

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

Now that our database has the correct naming of the tables and ids, we can just use belongsToMany and this works! There is no need for a AuthorBook model, Bookshelf.js does this for you!

Here's the advanced description: http://bookshelfjs.org/#Model-instance-belongsToMany

Upvotes: 2

Related Questions