Loopback "hasManyThrough" relationship. Where can I add it?
I have a User object and a Hobbie object, both have their models defined in the Loopback and I can see them in the API explorer.
I have a UserHobbie table that links User and Hobbie in relation to ManyToMany. I am trying to declare loopback hasManyThrough like
User.hasMany(Hobbie, {through: UserHobbie});
but i cant do it well as it is not showing in explorer . I declared it in /server/server.js
right after the bootstrap section and I tried to do it in /common/User.js
and /common/Hobbie.js
(but in any of them the other model is not visible).
Is there a correct syntax for adding this to User.json or Hobbie.json? This would be my preferred way as everything I entered in the json definition is displayed right in the explorer.
source to share
To solve the problem in your JSON model, I will describe the solution below. However, using the hasAndBelongsToMany relationship will solve your problem more easily, and I will describe it below as well.
In your User.json:
"relations": {
"Hobbies": {
"type": "hasMany",
"model": "Hobbie",
"through": "UserHobbie",
"foreignKey": "hobbieId"
}
}
Inside your Hobbie.json:
"relations": {
"Users": {
"type": "hasMany",
"model": "User",
"through": "UserHobbie",
"foreignKey": "userId"
}
}
Your UserHobbie.json will look like this (note that you DO NOT define userId OR hobbieId inside "properties":
{
"name": "UserHobbie",
"plural": "UserHobbies",
"base": "PersistedModel",
"properties": {
"id": {
"type": "String",
"id": true
}
},
"validations": [],
"relations": {
"Users": {
"type": "belongsTo",
"model": "User",
"foreignKey": "userId"
},
"Hobbies": {
"type": "belongsTo",
"model": "Hobbie",
"foreignKey": "hobbieId"
}
},
"acls": [],
"methods": []
}
THIS IS A SIMPLE WAY FOR THIS BELOW:
DO NOT CREATE the UserHobbies model. Loopback will automatically create a union model for you.
In your user model:
"relations": {
"Hobbies": {
"type": "hasAndBelongsToMany",
"model": "Hobbie"
}
}
Hobbie model inside of you:
"relations": {
"Users": {
"type": "hasAndBelongsToMany",
"model": "User"
}
}
If you want to do it in code, YOU'RE RIGHT, there are Bootstrap sync issues that prevent this relationship from appearing in explorer. I'll add another answer to show you how.
source to share
Now, in order for your original linking code implementation to appear in Explorer, here's what you need to do.
First, from the Loopback Projects./server/boot directory, move "explorer.js" to. / server (where server.js is in the project.
The last part. /server/server.js should look something like this (I've cut some of the comments for brevity.
boot(app, __dirname);
... // Removed for brevity
app.use(loopback.urlNotFound());
// The ultimate error handler.
app.use(loopback.errorHandler());
app.start = function() {
// start the web server
return app.listen(function() {
app.emit('started');
console.log('Web server listening at: %s', app.get('url'));
});
};
// start the server if `$ node server.js`
if (require.main === module) {
app.start();
}
Now EDIT the last part of the .server / server.js to look like this:
boot(app, __dirname);
// We took explorer.js out of /boot and put it in /server root next to server.js
var programmaticLoopbackSetup = require('./programmaticLoopbackSetup');
// If the User has any special Programmatic Loopback Setup (create Model Relationships, etc.) do it first
if (programmaticLoopbackSetup !== undefined) {
programmaticLoopbackSetup(app, finishUp);
}
else {
finishUp(); // If you didn't want any Code based Setup
}
// Defer all the rest of the Startup Work until Explorer
// has all the Model Info it needs from any Async or Programmatic Setup.
function finishUp() {
require('./explorer')(app);
// This was formerly done within "boot" above...
... // removed for brevity...
// Requests that get this far won't be handled
// by any middleware. Convert them into a 404 error
// that will be handled later down the chain.
app.use(loopback.urlNotFound());
// The ultimate error handler.
app.use(loopback.errorHandler());
app.start = function() {
// start the web server
return app.listen(function() {
app.emit('started');
console.log('Web server listening at: %s', app.get('url'));
});
};
// start the server if `$ node server.js`
if (require.main === module) {
app.start();
}
}
Add a new file to. /server/programmaticLoopbackSetup.js and make it look like below (notice how it is called after "loading" and before the application is finished initializing
module.exports = function programmaticLoopbackSetup(app, next) {
var User = app.models.User;
var Hobbie = app.models.Hobbie;
// This Block Below Creates a Many to Many User / Hobbie Relationship directly
User.hasAndBelongsToMany(Hobbie);
Hobbie.hasAndBelongsToMany(User);
next(); // Callback to finish App Init...
};
In this case, you will see the User / Hobbie relationship (using the hasAndBelongsToMany parameter in this case) in the explorer. Make WHATEVER Code LoopBack Model, Datasource or other refinements in LoopbackSetup.js programmer
source to share