Estus Flask
Estus Flask

Reputation: 222369

Always fetch from related models in Bookshelf.js

I would like baffle.where({id: 1}).fetch() to always get typeName attribute as a part of baffle model, without fetching it from baffleType explicitly each time.

The following works for me but it seems that withRelated will load relations if baffle model is fetched directly, not by relation:

let baffle = bookshelf.Model.extend({
    constructor: function() {
        bookshelf.Model.apply(this, arguments);

        this.on('fetching', function(model, attrs, options) {
            options.withRelated = options.withRelated || [];
            options.withRelated.push('type');           
        });
    },

    virtuals: {
        typeName: {
            get: function () {
                return this.related('type').attributes.typeName;
            }
        }
    },
    type: function () {
        return this.belongsTo(baffleType, 'type_id');
    }
});

let baffleType = bookshelf.Model.extend({});

What is the proper way to do that?

Upvotes: 10

Views: 3104

Answers (2)

JonG
JonG

Reputation: 182

This question is super old, but I'm answering anyway.

I solved this by just adding a new function, fetchFull, which keeps things pretty DRY.

let MyBaseModel = bookshelf.Model.extend({
  fetchFull: function() {
    let args;
    if (this.constructor.withRelated) {
      args = {withRelated: this.constructor.withRelated};
    }
    return this.fetch(args);
  },
};

let MyModel = MyBaseModel.extend({
    tableName: 'whatever',
  }, {
    withRelated: [
      'relation1',
      'relation1.related2'
    ]
  }
);

Then whenever you're querying, you can either call Model.fetchFull() to load everything, or in cases where you don't want to take a performance hit, you can still resort to Model.fetch().

Upvotes: 4

Satyajeet
Satyajeet

Reputation: 2044

Issue on repo is related to Fetched event, However Fetching event is working fine (v0.9.2).

So just for example if you have a 3rd model like

var Test = Bookshelf.model.extend({
   tableName : 'test',
   baffleField : function(){
       return this.belongsTo(baffle)
   } 
})

and then do Test.forge().fetch({ withRelated : ['baffleField']}), fetching event on baffle will fire. However ORM will not include type (sub Related model) unless you specifically tell it to do so by

Test.forge().fetch({ withRelated : ['baffleField.type']})

However I would try to avoid this if it is making N Query for N records.

UPDATE 1

I was talking about same thing that you were doing on fetching event like

fetch: function fetch(options) {
   var options = options || {}
   options.withRelated = options.withRelated || [];
   options.withRelated.push('type');    
    // Fetch uses all set attributes.
   return this._doFetch(this.attributes, options);
}

in model.extend. However as you can see, this might fail on version changes.

Upvotes: 8

Related Questions