Documentation for HasAndBelongsToMany relations is a bit confusing, and seems also outdated.
First, documentation starts by
A hasAndBelongsToMany relation creates a direct many-to-many connection with another model, with no intervening model.
Then, the schematic shows three different models, two related together and the last one seems a through model. It seems contradictory with the "no intervening model" statement.
Then, quick typo
For example, here is an excerpt from a model JSON
It may be intended but JSON examples are given for a student model, which is unrelated to the schematic above.
Then, after reading #226, is the following paragraph still valid ?
Adding a relation via REST API
When adding relation through the REST API, a join model must exist before adding relations.
For Example in the above example with "Assembly" and "Part" models, to add an instance of "Part" >to "Assembly" through the REST API interface an "AssemblyPart" model must exist for it to work.
I tried this morning and I was able to add relations without creating a "join" model. I'm not entirely sure but I believe this is deprecated.
Just thought of sharing some feedback.
Thank you @Overdrivr, the description is not accurate, hasAndBelongsToMany has no explicit intervening model and it will create an intervening model implicitly if not present, please check relation definition here to see more details.
excerpt is not a typo since it's just part of the whole .json file :)
And I think it makes sense to keep example consistent with UML above and tutorial "Adding a relation via REST API" below.
In /common/models/assembly.json:
{
"name": "Assembly",
"plural": "Assemblies",
"relations": {
"parts": {
"type": "hasAndBelongsToMany",
"model": "Part"
},
and in /common/models/assembly.js:
Part.hasAndBelongsToMany(Assembly);
Assembly.hasAndBelongsToMany(Part);
Any thoughts about the change here @crandmck ? Thank you!
I am afraid the join model still need to be existed, I create a sandbox to test it:
https://github.com/jannyHou/loopback-sandbox/tree/has-and-belongs-to-many
Space hasAndBelongsToMany Customer
if the join model spaceCustomer removed, user cannot add relation by space.customers.add(customer, function(err) { // Your code });
@jannyHou Your suggested change looks fine. Please go ahead and edit it yourself. Thanks!
I am closing it since changes are applied, thanks!
https://docs.strongloop.com/display/public/LB/HasAndBelongsToMany+relations#HasAndBelongsToManyrelations-DefiningahasAndBelongsToManyrelation
@jannyHou Thank you for the changes
Here is some feedback, sorry I haven't provided it earlier.
A hasAndBelongsToMany relation creates a direct many-to-many connection with another model, *with no intervening model.*
is contradictory with
When adding relation through the REST API, *a join model must exist* before adding relations.
As a user, I don't understand if I must or not create a join model, or if it's automatically managed by loopback.
Also, I disagree further with you regarding this join model. Using the REST API through the explorer
with this config https://github.com/Overdrivr/sandbox-hasAndBelongToMany
POST api\spaces
POST api\customers
PUT api\spaces\1\customers\rel\1
This effectively creates the relation without me having to create any join model. I believe it is not calling space.customer.add but instead space.customer.link
And also,
POST api\spaces
POST api\spaces\1\customers
also works just fine. I am not sure it is calling space.customers.add however it does creates a new customer and attachs it to space instance, which is pretty much what add does.
Could try my repo and see if you get the same results ?
@Overdrivr that's fine. thanks for your feedback, I am reopening it and I will retest it ASAP.
@Overdrivr you are right, this line means loopback will create an intervening model implicitly.
I run into error with .add() because I defined "through": "spaceCustomer" in relation in space.json.
Function space.customers.add() is defined here:
https://github.com/strongloop/loopback-datasource-juggler/blob/master/lib/relation-definition.js#L1555-L1561
But I cannot find function space.customers.link(), I will update the doc after confirming more details.
And finally the answer is, an existed intervening model is not required, but you need to create one if you want to add properties/remote methods/etc.. to it.
Hello guys.
Have been tinkering for a couple of hours and have realized that the implicit model creation only happen when one calls ds.automigrate() on the entire database
This makes through model creation very cumbersome for in production databases. I suggest that there be a way to create the implicit through model via ds.autoupdate as well.
ALTERNATIVELY.
Document a clear way to manually create the implicit through model and attach foreign keys.
The current documentation is quite confusing in this regard.
thanks @kodepareek I will take a look of your scenario asap.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This issue has been closed due to continued inactivity. Thank you for your understanding. If you believe this to be in error, please contact one of the code owners, listed in the CODEOWNERS file at the top-level of this repository.
@jannyHou Do you have an update on @kodepareek's scenario?
I am facing a similar issue, Did anyone ever document a clear way to manually create the implicit through model?
This still doesn't seem to be solved, is there any plan to clarify this?
@ValentinKlinghammer do you mean the following issue not clear?
Have been tinkering for a couple of hours and have realized that the implicit model creation only happen when one calls ds.automigrate() on the entire database
This makes through model creation very cumbersome for in production databases. I suggest that there be a way to create the implicit through model via ds.autoupdate as well.
@jannyHou Well... The question was more in the direction of wether there is intention to clarify the docs to the point where one could add a relation with an implicit through model from a base project and have it work.
It's just not clear from the docs how one should create the implicit through model or how to make sure that is does get created. It seems to me that, at least with the Postgres Connector, the implicit through model gets created if you loop through the right models in your auto-update script. But it took days of search to piece this together.
What worked for me in the end was the following autoupdate script. Notice that ds.modelBuilder.models has the implicit through model included whereas other model lists don't (such as model-config.json).
var path = require('path');
var app = require(path.resolve(__dirname, '..'));
var ds = app.datasources.db;
// By using modelBuilder.models, relations should be created automagically
var models = ds.modelBuilder.models;
var datasources = app.datasources;
if(ds.connected) {
updateAll();
} else {
ds.once('connected', updateAll);
}
function updateAll() {
Object.keys(models).forEach(function (key) {
const modelDs = models[key].getDataSource();
if (modelDs) {
modelDs.autoupdate(key, function (err) {
if (err) throw err;
console.log(`Model ${key} updated`);
});
return;
}
console.log(`Model ${key} has no datasource`);
});
}
Most helpful comment
Hello guys.
Have been tinkering for a couple of hours and have realized that the implicit model creation only happen when one calls
ds.automigrate()on the entire databaseThis makes through model creation very cumbersome for in production databases. I suggest that there be a way to create the implicit through model via
ds.autoupdateas well.ALTERNATIVELY.
Document a clear way to manually create the implicit through model and attach foreign keys.
The current documentation is quite confusing in this regard.