Question

In the Loopback documentation Initializing the application, it is said two things :

First :

Loopback.boot() loads data sources and models based on json definition files, or given options, then, loads all js files from models/ and boot/ directories

Then :

"Don't combine using app.boot() and app.model(name, config) in multiple files because it may result in models being undefined due to race conditions. To avoid this when using app.boot() make sure all models are passed as part of the models definition."

Doesn't the two seem a contradiction ?

I have many models to define, that I don't want to define in a single enormous json file, and hence want to place one js file per model in the said models/ directory to be loaded at boot time.

What I did, for the moment, is define a model in models/ExampleModel.js like so :

    var properties = {
        fieldOne: { type: String, required: true },
        otherField: { type: Number }
    };

    var options = {
        relations: {
            collections: {
                type: "belongsTo",
                model: "user"
            }
        }
    };

    var Model = require('loopback').Model;
    module.exports = Model.extend('ExampleModel', properties, options);

The thing is : during boot(), the model is loaded, but not attached to the app or any datasource. It is not exposed to REST API.

I tried a small addition to models.json to enable the model in the app :

"examplemodel": {
    "options": {
        "base": "ExampleModel"
    },
    "dataSource": "db",
    "public": true
}

It does not work, Loopback throw a Class not found exception.

I also thought about using app.model() instead of Model.extend(), but I don't know how to access app in the required model js files.

Question: how to define models in models/ directory and still attach them to app, datasource and REST API, while still relying on all boot() mechanism ?

Was it helpful?

Solution

I also thought about using app.model() instead of Model.extend(), but I don't know how to access app in the required model js files.

If you scaffolded your project using slc lb project, the app object should be exported by the main app.js file.

So you can get the app object this way:

// in models/example-model.js
var app = require('../app.js')

Once you have the app object, you can call app.model as you correctly pointed out.

var properties = {
  fieldOne: { type: String, required: true },
  otherField: { type: Number }
};

var options = {
    relations: {
        collections: {
            type: "belongsTo",
            model: "user"
        }
    }
};

app.model('ExampleModel', {
  properties: properties, 
  options: options,
  dataSource: 'db' // replace with the correct name
);

// you can access the model now via
//   app.models.ExampleModel

OTHER TIPS

I gave it a try, by realizing that required models (from models/ directory) are not stored anywhere, so I modified this, in the node_modules/loopback/lib/application.js :

498 - var requiredModels = requireDir(path.join(appRootDir, 'models'));
498 + app.requiredModels = requireDir(path.join(appRootDir, 'models'));

That way, I can access the required models after the app.boot() call in app.js :

app.boot(__dirname);
Object.keys(app.requiredModels).map(function(modelName) {
    app.model(modelName, {dataSource: 'db'});
});

It kinda works : model is exposed to the REST API, but not its relations, any ideas why ?

Also, I modified a core file from loopback distribution, so it will break at the next update...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top